/* csvorbis
 * Copyright (C) 2000 ymnk, JCraft,Inc.
 *  
 * Written by: 2000 ymnk<ymnk@jcraft.com>
 * Ported to C# from JOrbis by: Mark Crichton <crichton@gimp.org> 
 *   
 * Thanks go to the JOrbis team, for licencing the code under the
 * LGPL, making my job a lot easier.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
   
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


using System;
using csogg;

namespace csvorbis 
{
	public class Block
	{
		///necessary stream state for linking to the framing abstraction
		internal float[][] pcm=new float[0][]; // this is a pointer into local storage
		internal csBuffer opb=new csBuffer();
  
		internal int lW;
		internal int W;
		internal int nW;
		internal int pcmend;
		internal int mode;

		internal int eofflag;
		internal long granulepos;
		internal long sequence;
		internal DspState vd; // For read-only access of configuration

		// local storage to avoid remallocing; it's up to the mapping to
		// structure it
		//byte[] localstore;
		//int  localtop;
		//int  localalloc;
		//int  totaluse;
		//AllocChain reap;

		// bitmetrics for the frame
		internal int glue_bits;
		internal int time_bits;
		internal int floor_bits;
		internal int res_bits;

		public Block(DspState vd)
		{
			this.vd=vd;
			//  localalloc=0;
			//  localstore=null;
			if(vd.analysisp!=0)
			{
				opb.writeinit();
			}
		}

		public void init(DspState vd)
		{
			this.vd=vd;
		}

		//  int alloc(int bytes){
		//    bytes=(bytes+(8-1))&(~(8-1));
		//    if(bytes+localtop>localalloc){
		//      if(localstore!=null){
		//	AllocChain link=new AllocChain();
		//	totaluse+=localtop;
		//	link.next=reap;
		//	link.ptr=localstore;
		//	reap=link;
		//      }
		//      // highly conservative
		//      localalloc=bytes;
		//      localstore=new byte[localalloc];
		//      localtop=0;
		//    }
		//    {
		//      int foo=localtop;
		//      //void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
		//      localtop+=bytes;
		//      return foo;
		//    }
		//  }

		// reap the chain, pull the ripcord
		//  void ripcord(){
		//    // reap the chain
		//    while(reap!=null){
		//      AllocChain next=reap.next;
		//      //free(reap->ptr);
		//      reap.ptr=null;
		//      //memset(reap,0,sizeof(struct alloc_chain));
		//      //free(reap);
		//      reap=next;
		//    }
		//    // consolidate storage
		//    if(totaluse!=0){
		//      //vb->localstore=realloc(vb->localstore,vb->totaluse+vb->localalloc);
		//      byte[] foo=new byte[totaluse+localalloc];
		//      Array.Copy(localstore, 0, foo, 0, localstore.length);
		//      localstore=foo;
		//      localalloc+=totaluse;
		//      totaluse=0;
		//    }
		//    // pull the ripcord
		//    localtop=0;
		//    reap=null;
		//  }

		public int clear()
		{
			if(vd!=null)
			{
				if(vd.analysisp!=0)
				{
					opb.writeclear();
				}
			}
			//ripcord();
			//if(localstore!=null)
			//  localstore=null;
			//memset(vb,0,sizeof(vorbis_block));
			return(0);
		}

		public int synthesis(Packet op)
		{
			Info vi=vd.vi;
 
			// first things first.  Make sure decode is ready
			// ripcord();
			opb.readinit(op.packet_base, op.packet, op.bytes);

			// Check the packet type
			if(opb.read(1)!=0)
			{
				// Oops.  This is not an audio data packet
				return(-1);
			}

			// read our mode and pre/post windowsize
			int _mode=opb.read(vd.modebits);
			if(_mode==-1)return(-1);
  
			mode=_mode;
			W=vi.mode_param[mode].blockflag;
			if(W!=0)
			{
				lW=opb.read(1);
				nW=opb.read(1);
				if(nW==-1) return(-1);
			}
			else
			{
				lW=0;
				nW=0;
			}
  
			// more setup
			granulepos=op.granulepos;
			sequence=op.packetno-3; // first block is third packet
			eofflag=op.e_o_s;

			// alloc pcm passback storage
			pcmend=vi.blocksizes[W];
			//pcm=alloc(vi.channels);
			if(pcm.Length<vi.channels)
			{
				pcm=new float[vi.channels][];
			}
			for(int i=0;i<vi.channels;i++)
			{
				if(pcm[i]==null || pcm[i].Length<pcmend)
				{
					pcm[i]=new float[pcmend];
					//pcm[i]=alloc(pcmend);
				}
				else
				{
					for(int j=0;j<pcmend;j++){ pcm[i][j]=0; }
				}
			}

			// unpack_header enforces range checking
			int type=vi.map_type[vi.mode_param[mode].mapping];
			return(FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
		}
	}
}
