package turgen.tapeimage;

import java.util.*;
import java.io.*;
import turgen.FileFormatException;
import turgen.plugin.TapeImagePlugin;

public class TapeImage {

    private final Vector chunkVector;
    
    public TapeImage() {
        chunkVector=new Vector();
    }

    public int[] getChunkBilance() {

        int[] retVal = new int[2];
        int l = chunkVector.size();
        TapeImageChunk chunk;

        retVal[0]=l;    /*Total*/
        retVal[1]=0;    /*Unsupported*/

        boolean lastParentSupported=false;

        Iterator it = chunkVector.iterator();
        while(it.hasNext()) {
            chunk=(TapeImageChunk)it.next();

            /*Parent chunk ?*/
            if (chunk.isGeneretedUsingParent()==false) {
                lastParentSupported=TapeImagePlugin.isChunkSupported(chunk);
            }
            
            if (lastParentSupported==false) retVal[1]+=1;
        }
        

        return retVal;
    }

    public void parse(String filespec) throws Exception {
        
        FileInputStream fis=null;
        BufferedInputStream bis=null;

        char[] chunkTypeChars = new char[4];
        int[] chunkTypeInts = new int[4];
        
        try {

            /** Open tape image file*/
            fis = new FileInputStream(filespec);
            bis = new BufferedInputStream(fis);

            boolean isFujiRead=false;
            TapeImageChunk lastIndependentChunk=null;

            READLOOP:
            while(true) {

                /*Read next chunk while checking for EOF*/
                for(int i=0;i<4;i++) {

                    chunkTypeInts[i]=bis.read();

                    if (chunkTypeInts[i]==-1) {
                        if (i==0) break READLOOP;
                        else throw new FileFormatException("Trailing bytes in tape image");
                    }
                }

                /*Determine chunk type*/
                for(int i=0;i<4;i++) {
                    chunkTypeChars[i]=(char)chunkTypeInts[i];
                }
                String chunkType=new String(chunkTypeChars);
                

                /*Create new instance of appropriate chunks*/

                /*FUJI chunk*/
                if (chunkType.equals("FUJI")) {
                    FujiChunk fujiChunk = new FujiChunk();
                    fujiChunk.readFromStream(bis);
                    chunkVector.add(fujiChunk);
                    isFujiRead=true;
                    continue;
                }

                /*Other chunks only after FUJI chunk*/
                if (isFujiRead==false) {
                    throw new FileFormatException("FUJI chunk not found in tape image");
                }

                /*Baud chunk*/
                if (chunkType.equals("baud")) {
                    BaudChunk baudChunk = new BaudChunk();
                    baudChunk.readFromStream(bis);
                    chunkVector.add(baudChunk);
                    lastIndependentChunk=baudChunk;
                    continue;

                }
                
                if (chunkType.equals("fsk ")) {
                    FSKChunk fskChunk = new FSKChunk();
                    fskChunk.readFromStream(bis);
                    chunkVector.add(fskChunk);
                    continue;
                }

                /*Data chunk*/
                if (chunkType.equals("data")) {

                    TapeImageChunk parent;

                    /*If there is no preceding chunk, then we must create virtual parent*/
                    if (lastIndependentChunk==null) {
                        parent = new BaudChunk(600);
                    }
                    else {
                        parent = lastIndependentChunk;
                    }
                    
                    DataChunk dataChunk = new DataChunk(parent);
                    dataChunk.readFromStream(bis);
                    chunkVector.add(dataChunk);
                    continue;
                }

                /*Turbo chunks*/
                if (chunkType.startsWith("tr")) {

                    TurboChunk turboChunk = new TurboChunk(chunkType);
                    turboChunk.readFromStream(bis);
                    chunkVector.add(turboChunk);
                    lastIndependentChunk=turboChunk;
                    continue;
                }
                
                if (chunkType.equals("pwms")) {
                    PWMChunk pwmChunk = new PWMChunk(chunkType,null);
                    pwmChunk.readFromStream(bis);
                    lastIndependentChunk=pwmChunk;
                    chunkVector.add(pwmChunk);
                    continue;
                }
                
                if (chunkType.equals("pwmc") || chunkType.equals("pwmd") || chunkType.equals("pwml")) {
                    PWMChunk pwmChunk = new PWMChunk(chunkType,lastIndependentChunk);
                    pwmChunk.readFromStream(bis);
                    chunkVector.add(pwmChunk);
                    continue;
                }
                    

                /*Other chunks - they must be considered independent chunks*/
                UnknownChunk unknownChunk = new UnknownChunk(chunkType);
                unknownChunk.readFromStream(bis);
                chunkVector.add(unknownChunk);
                lastIndependentChunk=unknownChunk;
                
            }
        }
        
        finally {

            /**Attempt to close tape image file*/
            try {
                if (fis!=null) fis.close();
            }
            catch(Exception closeException) {
                closeException.printStackTrace();
            }
            
        }
    }


    public int getChunkCount() {
        return chunkVector.size();
    }

    public TapeImageChunk getChunkAt(int index) {
        return (TapeImageChunk)chunkVector.elementAt(index);
    }

    public String[] getListing() {

        int l = getChunkCount();
        String[] listing = new String[l];

        for(int i=0;i<l;i++) {
            listing[i]=getChunkAt(i).toString();
        }

        return listing;
     }
}
