package turgen.tapeimageextractor;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;
import turgen.Utils;
import turgen.tapeimage.TapeImage;
import turgen.tapeimage.TapeImageChunk;


public class TapeImageModel extends AbstractTableModel {

    private TapeImage tapeImage;
    private Vector<ExtractorChunk> extractorChunks;
    private static final int CI_CHUNKID=0;
    private static final int CI_CHUNKNAME=1;
    private static final int CI_IRG=2;
    private static final int CI_LENGTH=3;
    private static final int CI_HEAD=4;
    private static final int CI_TAIL=5;
    private static final int CI_HINT=6;
    private static final String unknownData = "?";
    
    public TapeImageModel() {
        createEmptyModel();
    }
    
    public void clear() {
        createEmptyModel();
        fireTableDataChanged();
    }
    
    public void openTapeImage(String filespec) throws Exception {
        /*Clear extractor chunks*/
        extractorChunks.clear();
        fireTableDataChanged();
        
        /*Open tape image*/
        tapeImage = new TapeImage();
        tapeImage.parse(filespec);
        
        /*Create extractor chunks*/
        TapeImageChunk tic;
        int numChunks = tapeImage.getChunkCount();
        
        for(int i=0;i<numChunks;i++) {
            extractorChunks.add(new ExtractorChunk(tapeImage.getChunkAt(i),i));
        }
        
        fireTableDataChanged();
        
    }
    
    public int getRowCount() {
        return extractorChunks.size();
    }

    public int getColumnCount() {
        return colNames.length;
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        ExtractorChunk chunk = extractorChunks.elementAt(rowIndex);
        
        if (chunk==null) return unknownData;
        
        switch(columnIndex) {
            
            case CI_CHUNKID: {
                return chunk.getId();
            }
            case CI_CHUNKNAME: {
                return chunk.getChunkName();
            }
            case CI_IRG: {
                return chunk.getIRGString();
            }
            case CI_LENGTH: {
                return chunk.getLengthString();
            }
            case CI_HEAD: {
                return chunk.getHeadString();
            }
            case CI_TAIL: {
                return chunk.getTailString();
            }
            case CI_HINT: {
                return chunk.getHintString();
            }
            default: {
                return unknownData;
            }
                
        }
    }
    
    private String[] colNames = {"#","Chunk","IRG","Length","Head","Tail","Hint"};
    
    public String getColumnName(int index) {
        return colNames[index];
    }
    
    public Class getColumnClass(int index) {
         return String.class;
     }
    
    private void createEmptyModel() {
        tapeImage = new TapeImage();
        extractorChunks = new Vector<ExtractorChunk>();
    }

    ExtractorChunk elementAt(int i) {
        return extractorChunks.elementAt(i);
    }

    void updateExtractionHints(int[] indexes, HintsCrate crate) {
        
        for(int i=0;i<indexes.length;i++) {
            int index = indexes[i];
            ExtractorChunk c = extractorChunks.elementAt(index);
            if (c.isExtractible()) {
                c.setHintsCrate(crate);
            }
        }
        
        fireTableDataChanged();
    }
    
    ExtractionReportCrate extractChunks(int[] indexes,String filespec,ExtractionReporter rep) throws Exception {
        
        ExtractionReportCrate reportCrate = new ExtractionReportCrate();
        ExtractorChunk.ExtractionCrate eCrate;
        
        FileOutputStream fos = new FileOutputStream(filespec);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        
        
        
        for(int i=0;i<indexes.length;i++) {
            ExtractorChunk chunk = elementAt(indexes[i]);
            reportCrate.totalChunks++;
            
            String id = Utils.padZeros(chunk.getId(), 4);
            
            /*We skip chunks that cannot be extracted*/
            if (chunk.isExtractible()==false) {
                reportCrate.skippedChunks++;
                rep.addMessage(id+":Not extractible");
                continue;
            }
            
            /*Extraction of one chunk*/
            eCrate = chunk.extractData();
            if (eCrate.completionCode!=ExtractorChunk.CC_OK) {
                switch (eCrate.completionCode) {
                    case ExtractorChunk.CC_BAD_HINT: {
                        rep.addMessage(id+":Bad hints");
                        reportCrate.badHintsChunks++;
                        break;
                    }
                    case ExtractorChunk.CC_BAD_LENGTH: {
                        rep.addMessage(id+":Bad length");
                        reportCrate.badHintsChunks++;
                        break;
                    }
                }
                
            }
            
            for(int k=0;k<eCrate.data.length;k++) {
                bos.write(eCrate.data[k]);
            }
            
        }
        
        /*Close output file*/
        bos.flush();
        bos.close();
        
        /*Report*/
        return reportCrate;
        
    }
   


}
