package turgen.plugin.csturbo;

import turgen.plugin.*;
import turgen.generator.SignalGenerator;
import turgen.config.Configuration;
import turgen.*;
import java.io.*;
import javax.swing.*;
import turgen.config.BooleanConfigEntry;
import turgen.config.ConfigClass;

import turgen.config.IntegerConfigEntry;
import turgen.dtb.*;
import turgen.playlist.AbstractPlayListItem;
import turgen.tapeimage.*;

public class Turbo2000Plugin implements Plugin {

    
    private String lastError;
    private CsTurboPluginsPanel panel;
    private InOutProvider ioProvider;
    private int[] casChunkName = {116,114,50,107};

    private ConfigClass cfcTurbo2000;
    private IntegerConfigEntry cfgPilotLenA;
    private IntegerConfigEntry cfgPilotLenB;
    private IntegerConfigEntry cfgPilotLenBlockLoading;
    private BooleanConfigEntry cfgPrependLoader;


    /** Nova instance SuperTurboPlugin */
    public Turbo2000Plugin() {
           
       
    }


    /** Identifikacni jmeno modulu*/
    public String getName() {
        return "Turbo 2000";

    }

    /*************************************************************/
    /*Tvorba instrukci pro generator*/
    public int[] getInstructions(AbstractPlayListItem _pl) {

        /*Get CsTurboPlaylistItem*/
        CsTurboPlaylistItem pl = (CsTurboPlaylistItem) _pl;


        try {

            /*Pripraven vystupni proud pro instrukce*/
            InstructionStream is = new InstructionStream();
            
            /*If loader is to be prepended, then we prepend it*/
            if (cfgPrependLoader.getAsBoolean()==true) {
                    is.add(LoaderBinaryData.universalTurboLoader);
            }
            

            /*Nastaveni, pro vsechny mozne konverze je nastaveni stejne,
             *bloky nebo soubory jsou vzdy v Super Turbu o dane rychlosti
             */
            Utils.addSetupInstruction(is, pl.pulses, casChunkName,SignalGenerator.FLAG_POLARITY_10,SignalGenerator.FLAG_ORDER_HL);

            /*Nyni se vybere konverze podle typu v polozce playlistu*/
            switch (pl.conversionType) {

                /*Zde se prevadi cely soubor*/
                case CsTurboPlaylistItem.CV_BINTURBO:
                case CsTurboPlaylistItem.CV_BASIC:
                case CsTurboPlaylistItem.CV_DATA: {
                    convertFullFile(is, pl);
                    break;
                }
                /*Monoliticky binarni soubor*/
                case CsTurboPlaylistItem.CV_MONOLITHIC: {
                    convertMonolithicBinary(is, pl);
                    break;
                }
                /*Specialni retezove zavadeni*/
                case CsTurboPlaylistItem.CV_SEGMENTED_CHAIN: {
                    convertChainLoading(is, pl);
                    break;
                }
                /*Specialni blokove zavadeni*/
                case CsTurboPlaylistItem.CV_SEGMENTED_BLOCK: {
                    convertBlockLoading(is, pl);
                    break;
                }
            }

            is.add(SignalGenerator.INSTR_END);

            /*Instrukce pro generatory*/
            return is.getInstructions();

        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage() == null) {
                lastError = "Unable to produce instructions: " + e.toString();
            } else {
                lastError = e.toString();
            }
            return null;

        }
    }

    public String getLastError() {
        return lastError;
    }

    public AbstractPlayListItem createItem() {
        CsTurboPlaylistItem dpr = panel.getRecord();
        dpr.pluginClass = Turgen.pluginManager.getPluginClassName(this);
        return dpr;
    }

    public void resetPanel() {
        panel.clear();
    }

    public String validateInput() {
        return panel.verify();
    }

    public JPanel getItemPanel() {
        return panel;
    }

    public void init() {
        panel = new CsTurboPluginsPanel(false);
        
        /*Initialize configuration class*/
        cfcTurbo2000 = new ConfigClass("Turbo2000", "Turbo 2000");

        /*Initialize configuration entries*/
        cfgPilotLenA = new IntegerConfigEntry("pilotLenA","Header block pilot tone length [pulse]", 3072, 256, 8192);
        cfgPilotLenB = new IntegerConfigEntry("pilotLenB","Data block pilot tone length [pulse]", 3072, 256, 8192);
        cfgPilotLenBlockLoading = new IntegerConfigEntry("pilotLenBlockLoading","Pilot tone length for BlockLoading [pulse]", 2048, 256, 8192);
        cfgPrependLoader = new BooleanConfigEntry("prependLoader","Prepend Universal Turbo loader",false);

        /*Add entries to the class*/
        cfcTurbo2000.addEntry(cfgPilotLenA);
        cfcTurbo2000.addEntry(cfgPilotLenB);
        cfcTurbo2000.addEntry(cfgPilotLenBlockLoading);
        cfcTurbo2000.addEntry(cfgPrependLoader);

        /*Register configuration class*/
        Configuration.registerClass(cfcTurbo2000);
        
    }

    public void fillPanel(AbstractPlayListItem plr) {
        CsTurboPlaylistItem dpr = (CsTurboPlaylistItem) plr;
        panel.fill(dpr);
    }

    public void setInOutProvider(InOutProvider prov) {
        ioProvider = prov;
        panel.setIOProvider(prov);
        
    }

    private void convertFullFile(InstructionStream is, CsTurboPlaylistItem cpi) throws Exception {

        int plenA = cfgPilotLenA.getAsInt();
        int plenB = cfgPilotLenA.getAsInt();
        
       
        int hdrLoad = Integer.parseInt(cpi.load);
        int hdrRun = Integer.parseInt(cpi.run);
        int hdrLength = Integer.parseInt(cpi.length);
        int hdrType = Integer.parseInt(cpi.type);

        /*Header*/
        
        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(plenA);
        is.add(SignalGenerator.INSTR_SYNC);

        is.add(SignalGenerator.INSTR_DATA);
        is.add(19);

        int[] hdr = Utils.createT2KHeader(cpi.fname, hdrType, hdrLoad, hdrLength, hdrRun);
        
        is.add(hdr);
        
        /*Safety pulse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_BLOCKSEP);
        


        /*DATA*/
        int[] fileData = readFileData(cpi.inFile, 0, Integer.MAX_VALUE);

        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(plenB);
        is.add(SignalGenerator.INSTR_SYNC);

        is.add(SignalGenerator.INSTR_DATA);
        is.add(fileData.length + 2);

        int chsum = 255;
        is.add(chsum);
        for (int i = 0; i < fileData.length; i++) {
            chsum ^= fileData[i];
        }
        is.add(fileData);
        is.add(chsum);
        /*Safety pulse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_BLOCKSEP);

    }

    private void convertMonolithicBinary(InstructionStream is, CsTurboPlaylistItem cpi) throws Exception {

        int hdrLoad = Integer.parseInt(cpi.load);
        int hdrRun = Integer.parseInt(cpi.run);
        int hdrLength = Integer.parseInt(cpi.length);
        int hdrType = Integer.parseInt(cpi.type);

        int plenA = cfgPilotLenA.getAsInt();
        int plenB = cfgPilotLenA.getAsInt();

       

        /*HLAVICKA*/
        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(plenA);
        is.add(SignalGenerator.INSTR_SYNC);

        is.add(SignalGenerator.INSTR_DATA);
        is.add(19);

        int[] hdr = Utils.createT2KHeader(cpi.fname, hdrType, hdrLoad, hdrLength, hdrRun);
        
        is.add(hdr);
        
        /*Safety pulse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_BLOCKSEP);

        /*DATA*/
        DOS2Binary dtb = new DOS2Binary(cpi.inFile);
        dtb.analyzeFromFile();

        int[] fileData = dtb.getFirstDataSegment().data;

        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(plenB);
        is.add(SignalGenerator.INSTR_SYNC);

        is.add(SignalGenerator.INSTR_DATA);
        is.add(fileData.length + 2);

        int chsum = 255;
        is.add(chsum);
        for (int i = 0; i < fileData.length; i++) {
            chsum ^= fileData[i];
        }
        is.add(fileData);
        is.add(chsum);

        /*Safety pluse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_BLOCKSEP);
    }

    private void convertChainLoading(InstructionStream is, CsTurboPlaylistItem cpi) throws Exception {


        int currentPause = 0;
        int plen = cpi.silenceList.length;

        File f = null;



        /*Nejprve se vytvori instance DOS2Binary*/
        DOS2Binary ae = new DOS2Binary(cpi.inFile);
        ae.analyzeFromFile();
        ae.prepareForDumbLoader();

        /*Mirne navyseni poctu zavadecich pulzu*/

        int currentPilotLenA = cfgPilotLenA.getAsInt();
        int currentPilotLenB = cfgPilotLenB.getAsInt();

       
        /*CHAINLOADER*/
        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(currentPilotLenA);
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_DATA);
        is.add(19);

        /*Adresy*/
        int ls = 0;
        int ll = 0;
        int lr = 0;
        lr = chainLoader_run;
        ll = chainLoader_data.length;
        ls = chainLoader_load;

        int[] header = Utils.createT2KHeader(cpi.fname, 3, ls, ll, lr);

        /*Zapsat do proudu*/
        is.add(header);
        

        /*Safety pulse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_SHORTSILENCE);
        is.add(SignalGenerator.INSTR_SHORTSILENCE);

        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(currentPilotLenB);
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_DATA);
        is.add(ll + 2);

        /*Data zavadece*/
        int p = 255;
        is.add(255);

        for (int k = 0; k < ll; k++) {
            
            p = p ^ chainLoader_data[k];
        }
        is.add(chainLoader_data);
        /*Kontroni soucet*/
        is.add(p);
        
        /*Safety pulse + pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_LONGSILENCE);
        is.add(3);

        /*Instrukce pro vygenerovani zavadece jsou jiz hotove*/
        int currentSegment = 0;
        int realCounter = 0;

        boolean initTag = false;

        while (currentSegment < ae.allSegments.size()) {

            /*Vezmeme segment*/
            Segment sct = (Segment) ae.allSegments.get(currentSegment);
            initTag = false;

            /*Zavadeci tony*/
            is.add(SignalGenerator.INSTR_PILOTTONE);
            is.add(currentPilotLenA);
            is.add(SignalGenerator.INSTR_NARROW);
            is.add(SignalGenerator.INSTR_DATA);
            is.add(19);


            /*Do hlavicky radeji cislo segmentu*/
            String s1 = Integer.toString(currentSegment);
            String s2 = Integer.toString(ae.allSegments.size() - 1);
            s1 = " " + s1 + "/" + s2;
            if (s1.length() > 8) {
                s1 = s1.substring(0, 8);
            }
            header = Utils.createT2KHeader(s1, 3, 0, 0, 0);

            int progress = 1;

            /*Podle typu segmentu*/
            switch (sct.type) {
                /*Datovy segment*/
                case (Segment.DATA_SEGMENT): {

                    int mark = 68;
                    lr = sct.start;
                    /*Neni-li to posledni segment*/
                    if (currentSegment < ae.allSegments.size() - 1) {

                        /*Podivat se jestli nenasleduje INIT nebo RUN*/
                        Segment js = (Segment) ae.allSegments.get(currentSegment + 1);
                        if (js.type == Segment.RUN_SEGMENT) {
                            lr = js.jump;
                            mark = 88;
                            progress = 2;
                            if (currentSegment == ae.allSegments.size() - 2) {
                                mark += 128;
                            }
                        }
                        if (js.type == Segment.INIT_SEGMENT) {
                            lr = js.jump;
                            mark = 89;
                            progress = 2;
                            initTag = true;
                            if (currentSegment == ae.allSegments.size() - 2) {
                                mark += 128;
                            }
                        }
                    }
                    /*Je-li posledni, pak typ segmentu bude oznacen inverzne*/
                    if (currentSegment == ae.allSegments.size() - 1) {
                        mark += 128;
                    }

                    header[2] = mark;
                    ls = sct.start;
                    ll = sct.data.length;

                    header[11] = realCounter;
                    realCounter++;

                    header[12] = ls % 256;
                    header[13] = ls / 256;
                    header[14] = ll % 256;
                    header[15] = ll / 256;
                    header[16] = lr % 256;
                    header[17] = lr / 256;
                    p = 0;
                    for (int i = 1; i < 18; i++) {
                        p = p ^ header[i];
                    }
                    header[18] = p;
                    
                    is.add(header);
                    
                    break;
                }
                /*INIT segment*/
                case (Segment.INIT_SEGMENT): {
                    int mark = 73;
                    /*Je-li posledni, pak se typ segmentu bude oznacen inverzne*/
                    if (currentSegment == ae.allSegments.size() - 1) {
                        mark += 128;
                    }

                    header[2] = mark;
                    ls = 738;
                    ll = 2;
                    lr = sct.jump;
                    header[11] = realCounter;
                    realCounter++;
                    header[12] = ls % 256;
                    header[13] = ls / 256;
                    header[14] = ll % 256;
                    header[15] = ll / 256;
                    header[16] = lr % 256;
                    header[17] = lr / 256;
                    p = 0;
                    for (int i = 1; i < 18; i++) {
                        p = p ^ header[i];
                    }
                    header[18] = p;
                    is.add(header);
                    
                    initTag = true;
                    break;
                }
                /*RUN segment*/
                case (Segment.RUN_SEGMENT): {

                    int mark = 82;
                    /*Je-li posledni, pak se typ segmentu bude oznacen inverzne*/
                    if (currentSegment == ae.allSegments.size() - 1) {
                        mark += 128;
                    }

                    header[2] = mark;
                    ls = 736;
                    ll = 2;
                    lr = sct.jump;
                    header[11] = realCounter;
                    realCounter++;
                    header[12] = ls % 256;
                    header[13] = ls / 256;
                    header[14] = ll % 256;
                    header[15] = ll / 256;
                    header[16] = lr % 256;
                    header[17] = lr / 256;
                    p = 0;
                    for (int i = 1; i < 18; i++) {
                        p = p ^ header[i];
                    }
                    header[18] = p;
                    is.add(header);
                    
                    break;
                }
                case (Segment.RUNINIT_SEGMENT): {
                    int mark = 75;
                    /*Je-li posledni, pak se typ segmentu bude oznacen inverzne*/
                    if (currentSegment == ae.allSegments.size() - 1) {
                        mark += 128;
                    }

                    header[2] = mark;
                    ls = 736;
                    ll = 4;
                    lr = 736;

                    header[11] = realCounter;
                    realCounter++;
                    header[12] = ls % 256;
                    header[13] = ls / 256;
                    header[14] = ll % 256;
                    header[15] = ll / 256;
                    header[16] = lr % 256;
                    header[17] = lr / 256;
                    p = 0;
                    for (int i = 1; i < 18; i++) {
                        p = p ^ header[i];
                    }
                    header[18] = p;
                    
                    is.add(header);
                    
                    break;
                }
            }

            /*RealCounter nesmi prekrocit 255*/
            if (realCounter == 255) {
                throw new DOS2BinaryException("Fatal: Chainloader can't handle more than 254 segments");
            }

            /*Safety pulse + safety pause*/
            is.add(SignalGenerator.INSTR_NARROW);
            is.add(SignalGenerator.INSTR_BLOCKSEP);

            /*Hlavicka je zapsana*/
            /*Po hlavicce*/
            is.add(SignalGenerator.INSTR_PILOTTONE);
            is.add(currentPilotLenB);
            is.add(SignalGenerator.INSTR_NARROW);
            is.add(SignalGenerator.INSTR_DATA);

            /*Opet podle segmentu*/
            switch (sct.type) {

                /*Datovy segment*/
                case (Segment.DATA_SEGMENT): {
                    p = 255;

                    is.add(ll + 2);

                    is.add(255);
                    for (int k = 0; k < ll; k++) {
                        p = p ^ sct.data[k];
                    }
                    is.add(sct.data);
                    /*Kontroni soucet*/
                    is.add(p);
                    break;
                }

                /*RUNINIT segment*/
                case (Segment.RUNINIT_SEGMENT): {
                    p = 255;
                    is.add(6);
                    is.add(p);
                    is.add(sct.jump % 256);
                    p = p ^ (sct.jump % 256);
                    is.add(sct.jump / 256);
                    p = p ^ (sct.jump / 256);
                    is.add(sct.jump2 % 256);
                    p = p ^ (sct.jump2 % 256);
                    is.add(sct.jump2 / 256);
                    p = p ^ (sct.jump2 / 256);
                    is.add(p);
                    break;
                }

                /*INIT segment*/
                case (Segment.INIT_SEGMENT): {
                    p = 255;
                    is.add(4);
                    is.add(p);
                    is.add(sct.jump % 256);
                    p = p ^ (sct.jump % 256);
                    is.add(sct.jump / 256);
                    p = p ^ (sct.jump / 256);
                    is.add(p);
                    break;
                }

                case (Segment.RUN_SEGMENT): {
                    p = 255;
                    is.add(4);
                    is.add(p);
                    is.add(sct.jump % 256);
                    p = p ^ (sct.jump % 256);
                    is.add(sct.jump / 256);
                    p = p ^ (sct.jump / 256);
                    is.add(p);
                    break;
                }
            }

            /*Safety pulse + safety pause*/
            is.add(SignalGenerator.INSTR_NARROW);
            is.add(SignalGenerator.INSTR_BLOCKSEP);


            /*Mozna prestavka za INIT*/
            if (initTag == true) {
                if (currentPause < plen) {
                    is.add(SignalGenerator.INSTR_LONGSILENCE);
                    is.add(cpi.silenceList[currentPause]);
                    currentPause++;
                }
            }

            

            currentSegment += progress;


        } /*Konec while*/
    }

    private void convertBlockLoading(InstructionStream is, CsTurboPlaylistItem cpi) throws Exception {


        int currentPause = 0;
        int plen = cpi.silenceList.length;

        File f = null;


        /*Nejprve se vytvori instance DOS2Binary*/
        DOS2Binary ae = new DOS2Binary(cpi.inFile);
        ae.analyzeFromFile();
        ae.prepareForDumbLoader();


        /*Loader*/
        int plenA = cfgPilotLenA.getAsInt();
        int plenB = cfgPilotLenB.getAsInt();
        int plenK = cfgPilotLenBlockLoading.getAsInt();

        

        /*Tvorba instrukci pro loader*/
        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(plenA);
        is.add(SignalGenerator.INSTR_SYNC);
        is.add(SignalGenerator.INSTR_DATA);
        is.add(19);


        /*Adresy*/
        int ls = 0;
        int ll = 0;
        int lr = 0;
        lr = blockLoader_run;
        ll = blockLoader_data.length;
        ls = blockLoader_load;

        int[] header = Utils.createT2KHeader(cpi.fname, 3, ls, ll, lr);


        /*Zapsat do souboru*/
        
        is.add(header);
        

        /*Safety pulse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_BLOCKSEP);

        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(plenB);
        is.add(SignalGenerator.INSTR_SYNC);
        is.add(SignalGenerator.INSTR_DATA);
        is.add(ll + 2);

        /*Data zavadece*/
        int p = 255;
        is.add(255);

        /*Vytvori se kopie*/
        int[] bl_data = new int[blockLoader_data.length];
        for(int i=0;i<bl_data.length;i++) {
            bl_data[i]=blockLoader_data[i];
        }

        /*Tabulka segmentu*/

        /*Tvorba tabulky, ne vic nez 62 segmentu*/
        int sl = ae.allSegments.size();
        if (sl > 62) {
            throw new DOS2BinaryException("Binary file has more than 62 segments. BlockLoading not possible");
        }

        Segment s;
        int index = blockLoader_table_offset;
        bl_data[blockLoader_counter_offset] = sl * 4;

        for (int i = 0; i < sl; i++) {
            s = (Segment) ae.allSegments.get(i);
            bl_data[index] = (s.start) % 256;
            bl_data[index + 1] = (s.start) / 256;
            bl_data[index + 2] = (s.stop + 1) % 256;
            bl_data[index + 3] = (s.stop + 1) / 256;
            index += 4;
        }
        for (int k = 0; k < ll; k++) {
            p = p ^ bl_data[k];
        }
        is.add(bl_data);
        /*Kontroni soucet*/
        is.add(p);
        is.add(SignalGenerator.INSTR_NARROW);

        /*Pauza 3 sekundy*/
        is.add(SignalGenerator.INSTR_LONGSILENCE);
        is.add(3);

        int currentSegment = 0;

        while (currentSegment < ae.allSegments.size()) {

            /*Vezmeme segment*/
            Segment sct = (Segment) ae.allSegments.get(currentSegment);

            is.add(SignalGenerator.INSTR_PILOTTONE);
            is.add(plenK);
            is.add(SignalGenerator.INSTR_SYNC);
            is.add(SignalGenerator.INSTR_DATA);

            p = 0;

            /*Mnozstvi dat: delka segmentu + 2 bajty, zacina se 255*/
            is.add(sct.stop - sct.start + 1 + 2);
            is.add(0);
            for (int k = 0; k < sct.data.length; k++) {
                p = p ^ sct.data[k];
            }
            is.add(sct.data);

            /*Kontroni soucet*/
            is.add(p);

            /*Safety pluse + safety pause*/
            is.add(SignalGenerator.INSTR_NARROW);
            is.add(SignalGenerator.INSTR_BLOCKSEP);

            /*Mozna prestavka za INIT*/
            if (sct.type == Segment.INIT_SEGMENT || sct.type == Segment.RUNINIT_SEGMENT) {
                if (currentPause < plen) {
                    is.add(SignalGenerator.INSTR_LONGSILENCE);
                    is.add(cpi.silenceList[currentPause]);
                    currentPause++;
                }
            }

            

            currentSegment++;
        } /*Konec while*/



    }

    private int[] readFileData(String file, int skipBytes, int maxLen) throws Exception {

        byte[] b;
        RandomAccessFile raf = new RandomAccessFile(file, "r");

        int flen = (int) raf.length();
        if (flen > maxLen) {
            raf.close();
            throw new FileTooLargeException("File exceeds " + Integer.toString(maxLen) + " bytes");
        }

        b = new byte[flen - skipBytes];
        raf.skipBytes(skipBytes);
        raf.readFully(b);
        raf.close();


        /*Konverze na int*/
        int[] fileData = new int[b.length];
        for (int i = 0; i < b.length; i++) {
            fileData[i] = b[i] < 0 ? b[i] + 256 : b[i];
        }

        return fileData;
    }

    public String[] getSupportedTapeImageChunks() {
        return new String[] {"tr2k"};
    }

    

    /**************************************************************************/
    /**************************************************************************/
    
    static int chainLoader_load = 1800;
    static int chainLoader_run = 1800;
    static int[] chainLoader_data = {0x20,0x9f,0x08,0x4c,0x16,0x07,0xa2,0xff,0x8e,0xfc,0x02,0x20,0xfc,0xfd,0xa9,0x08,0x85,0x33,0x85,0x35,0xa9,0x8c,0x85,0x34,0xa9,0x7b,0x85,0x32,0xa9,0x00,0x20,0xab,0x07,
0x90,0xeb,0x18,0xad,0x85,0x08,0xcd,0x7a,0x08,0xf0,0x05,0xa9,0x01,0x4c,0x0e,0x07,0xad,0x86,0x08,0x85,0x32,0x18,0x6d,0x88,0x08,0x85,0x34,0xad,0x87,0x08,0x85,0x33,
0x6d,0x89,0x08,0x85,0x35,0xa9,0xff,0x20,0xab,0x07,0xb0,0x05,0xa9,0x04,0x4c,0x0e,0x07,0xea,0xad,0x7c,0x08,0x29,0x7f,0xc9,0x52,0xf0,0x37,0xc9,0x44,0xf0,0x33,0xc9,
0x49,0xf0,0x26,0xc9,0x58,0xf0,0x07,0xc9,0x59,0xf0,0x12,0x4c,0x92,0x07,0xad,0x8a,0x08,0x8d,0xe0,0x02,0xad,0x8b,0x08,0x8d,0xe1,0x02,0x4c,0x9b,0x07,0xad,0x8a,0x08,
0x8d,0xe2,0x02,0xad,0x8b,0x08,0x8d,0xe3,0x02,0x20,0x98,0x07,0x4c,0x9b,0x07,0x6c,0xe2,0x02,0xad,0x7c,0x08,0x29,0x80,0xf0,0x03,0x6c,0xe0,0x02,0xee,0x7a,0x08,0x4c,
0x16,0x07,0x85,0x36,0xa9,0x34,0x8d,0x02,0xd3,0x8d,0x03,0xd3,0xa9,0x80,0x85,0x10,0x8d,0x0e,0xd2,0x18,0xa0,0x00,0x84,0x30,0x84,0x31,0x8c,0x0e,0xd4,0x8c,0x00,0xd4,
0x08,0xd0,0x70,0x20,0x55,0x08,0x90,0xf9,0xa9,0x00,0x85,0x2e,0x85,0x37,0xa0,0xb4,0x20,0x50,0x08,0x90,0xec,0xc0,0xd8,0x90,0xea,0xe6,0x2e,0xd0,0xf1,0xc6,0x37,0xa0,
0xd1,0x20,0x55,0x08,0x90,0xdb,0xc0,0xde,0xb0,0xf5,0x20,0x55,0x08,0x90,0x44,0xa0,0xc6,0x4c,0x17,0x08,0x28,0xd0,0x08,0xa5,0x36,0x45,0x2f,0xd0,0x37,0xf0,0x0c,0xa0,
0x00,0xa5,0x2f,0x91,0x32,0xe6,0x32,0xd0,0x02,0xe6,0x33,0xa0,0xc8,0x08,0xa9,0x01,0x85,0x2f,0x20,0x50,0x08,0x90,0x1c,0xc0,0xe3,0x26,0x2f,0xa0,0xc6,0x90,0xf3,0xa5,
0x31,0x45,0x2f,0x85,0x31,0xa5,0x32,0xc5,0x34,0xa5,0x33,0xe5,0x35,0x90,0xc5,0xa9,0x00,0xc5,0x31,0x68,0xa9,0xc0,0x8d,0x0e,0xd4,0x85,0x10,0x8d,0x0e,0xd2,0xa9,0x3c,
0x8d,0x02,0xd3,0x8d,0x03,0xd3,0x60,0x20,0x55,0x08,0x90,0x24,0xa2,0x04,0xca,0xd0,0xfd,0xa5,0x30,0x4a,0x25,0x37,0x8d,0x1a,0xd0,0xc8,0xf0,0x13,0xa5,0x11,0xf0,0x0d,
0xad,0x0f,0xd2,0x29,0x10,0xc5,0x30,0xf0,0xf0,0x85,0x30,0x38,0x60,0xc6,0x11,0x18,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x53,0x20,0x43,0x48,0x41,0x49,0x4e,0x4c,0x4f,0x41,0x44,0x45,0x52,0x9b,0xa2,0x90,0xa0,0x08,0x20,0x42,0xc6,0xa9,0x01,0x8d,
0xfc,0x02,0x20,0xfc,0xfd,0xa9,0x00,0x8d,0x44,0x02,0xa9,0x01,0x85,0x09,0x60};

    

    private static final int blockLoader_run = 2048;
    private static final int blockLoader_load = 2048;
    private static final int blockLoader_counter_offset = 0x143;
    private static final int blockLoader_table_offset = 0x144;

    private static final int[] blockLoader_data = {0x4c,0xd2,0x08,0x85,0x36,0xa9,0x34,0x8d,0x02,0xd3,0x8d,0x03,0xd3,0xa9,0x80,0x85,0x10,0x8d,0x0e,0xd2,0x18,0xa0,0x00,0x84,0x30,0x84,0x31,0x8c,0x0e,0xd4,0x8c,0x00,0xd4,
0x08,0xd0,0x70,0x20,0xad,0x08,0x90,0xf9,0xa9,0x00,0x85,0x2e,0x85,0x37,0xa0,0xb4,0x20,0xa8,0x08,0x90,0xec,0xc0,0xd8,0x90,0xea,0xe6,0x2e,0xd0,0xf1,0xc6,0x37,0xa0,
0xd1,0x20,0xad,0x08,0x90,0xdb,0xc0,0xde,0xb0,0xf5,0x20,0xad,0x08,0x90,0x44,0xa0,0xc6,0x4c,0x6f,0x08,0x28,0xd0,0x08,0xa5,0x36,0x45,0x2f,0xd0,0x37,0xf0,0x0c,0xa0,
0x00,0xa5,0x2f,0x91,0x32,0xe6,0x32,0xd0,0x02,0xe6,0x33,0xa0,0xc8,0x08,0xa9,0x01,0x85,0x2f,0x20,0xa8,0x08,0x90,0x1c,0xc0,0xe3,0x26,0x2f,0xa0,0xc6,0x90,0xf3,0xa5,
0x31,0x45,0x2f,0x85,0x31,0xa5,0x32,0xc5,0x34,0xa5,0x33,0xe5,0x35,0x90,0xc5,0xa9,0x00,0xc5,0x31,0x68,0xa9,0xc0,0x8d,0x0e,0xd4,0x85,0x10,0x8d,0x0e,0xd2,0xa9,0x3c,
0x8d,0x02,0xd3,0x8d,0x03,0xd3,0x60,0x20,0xad,0x08,0x90,0x24,0xa2,0x04,0xca,0xd0,0xfd,0xa5,0x30,0x4a,0x25,0x37,0x8d,0x1a,0xd0,0xc8,0xf0,0x13,0xa5,0x11,0xf0,0x0d,
0xad,0x0f,0xd2,0x29,0x10,0xc5,0x30,0xf0,0xf0,0x85,0x30,0x38,0x60,0xc6,0x11,0x18,0x60,0x20,0x53,0x0a,0xa9,0x00,0x8d,0x40,0x09,0xa2,0x0c,0x8e,0xfc,0x02,0xa9,0x01,
0x20,0xfc,0xfd,0xad,0x40,0x09,0xcd,0x43,0x09,0xd0,0x03,0x6c,0xe0,0x02,0xa9,0x41,0x8d,0xe2,0x02,0xa9,0x09,0x8d,0xe3,0x02,0xac,0x40,0x09,0xb9,0x44,0x09,0x85,0x32,
0xc8,0xb9,0x44,0x09,0x85,0x33,0xc8,0xb9,0x44,0x09,0x85,0x34,0xc8,0xb9,0x44,0x09,0x85,0x35,0xa9,0x00,0xa2,0x00,0xa0,0x00,0x20,0x03,0x08,0xb0,0x0d,0xa9,0xff,0x8d,
0xfc,0x02,0xa9,0x04,0x20,0xfc,0xfd,0x4c,0xd2,0x08,0x20,0x3d,0x09,0xee,0x40,0x09,0xee,0x40,0x09,0xee,0x40,0x09,0xee,0x40,0x09,0x4c,0xe4,0x08,0x6c,0xe2,0x02,0x00,
0x60,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x54,0x53,0x20,0x42,0x4c,0x4f,0x43,0x4b,0x4c,0x4f,0x41,0x44,0x45,0x52,0x9b,0xa2,0x44,0xa0,0x0a,0x20,0x42,0xc6,0xa9,0x00,0x8d,0x44,0x02,0xa9,0x01,
0x85,0x09,0x60};

    public void addInstructionsForChunk(InstructionStream is, TapeImageChunk chunk) throws Exception {

        /*trXX chunk*/
        if (chunk instanceof TurboChunk) {
            Utils.addSetupInstruction(is, Turgen.pulseCache.getPulsesForPlugin(this)[0], this.casChunkName,SignalGenerator.FLAG_POLARITY_10,SignalGenerator.FLAG_ORDER_HL);
            return;
        }

        /*Only data chunk accepted*/
        if (!(chunk instanceof DataChunk)) return;
        DataChunk dataChunk = (DataChunk)chunk;

        /*Zavadeci ton a data bloku*/
        is.add(SignalGenerator.INSTR_PILOTTONE);
        is.add(dataChunk.getAux());

        /*Synchropulz*/
        is.add(SignalGenerator.INSTR_SYNC);

        /*Data bloku*/
        is.add(SignalGenerator.INSTR_DATA);
        is.add(dataChunk.getLength());

        int[] dta = dataChunk.getData();
        is.add(dta);

        /*Safety pulse + safety pause*/
        is.add(SignalGenerator.INSTR_NARROW);
        is.add(SignalGenerator.INSTR_BLOCKSEP);
        
    }

    public BinaryConvertor[] getBinaryConvertors() {
        BinaryConvertor[] bc = new BinaryConvertor[3];
        MonolithicBinaryConvertor mbc = new MonolithicBinaryConvertor(false,this);
        ChainloadingBinaryConvertor cbc = new ChainloadingBinaryConvertor(false, 1800, 2191,this);
        BlockloadingBinaryConvertor bbc = new BlockloadingBinaryConvertor(false, 2048, 2627,this);
        bc[0]=mbc;
        bc[1]=cbc;
        bc[2]=bbc;
        return bc;
    }

    public String getCountry() {
        return "CS";
    }

    public boolean isUsingAlternateFileChooser() {
        return false;
    }


}
