package turgen.generator;

import java.io.*;
import turgen.Turgen;
import turgen.Utils;
import turgen.config.*;
import turgen.playlist.AbstractPlayListItem;


public class TapeImageGenerator implements Runnable,ProgressSource {
    
    /*Configuration entries*/
    private static ConfigClass cfcTapeImageGenerator;
    private static StringConfigEntry cfgTIOStandard;
    private static StringConfigEntry cfgTIOPostProcessingCommand;
    private static BooleanConfigEntry cfgTIOAutoCreateTempFile;

    /*PostProcessing*/
    private final boolean postProcessingEnabled;

    private int cancelType=ProgressSource.CANCEL_NO;
    private final int percent=0;
    
    private String errorMessage=null;
    private final int[] instr;
    private final AbstractPlayListItem playListItem;
    private final boolean renameToCas;
    private boolean postProcessingRun=false;
    
    public static void init() {

        /*Initialize configuration class*/
        cfcTapeImageGenerator = new ConfigClass("TapeImageGenerator","Tape image generator");

        /*Initialize configuration entries*/
        cfgTIOStandard = new StringConfigEntry("standard","Tape image chunks","pwmX",new String[] {"trXX","pwmX"});
        cfgTIOAutoCreateTempFile=new BooleanConfigEntry("autoCreateTempFile","Auto create temporary files",false);
        cfgTIOPostProcessingCommand= new StringConfigEntry("postProcessingCommand","Postprocessing command",null);

        /*Add entries to the class*/
        cfcTapeImageGenerator.addEntry(cfgTIOStandard);
        cfcTapeImageGenerator.addEntry(cfgTIOAutoCreateTempFile);
        cfcTapeImageGenerator.addEntry(cfgTIOPostProcessingCommand);
        
        /*Register configuration class*/
        Configuration.registerClass(cfcTapeImageGenerator);
        
    }
    
    
    public TapeImageGenerator(int[] instr, AbstractPlayListItem api,boolean rename,boolean postProEnabled) {
        this.instr=instr;
        playListItem=api;
        renameToCas=rename;
        postProcessingEnabled=postProEnabled;
        
    }
    
    
    public void run () {
        
        /*Zaregistrovat*/
        if (!Turgen.sync.registerProgress(this, Thread.currentThread())) {
            Turgen.dlm.frmTurgen.getStatusObject().addFailedTapeImages();
            return;
        }
        
        try {

            /*Tvorba souboru dat z instrukci*/
            int casData[]=null;

            if (cfgTIOStandard.getAsString().equals("trXX")) {

                TapeImageTRGenerator trTapeImage = new TapeImageTRGenerator();
                casData = trTapeImage.getData(instr);
            }
            else {
                TapeImagePWMGenerator pwmTapeImage = new TapeImagePWMGenerator();
                casData = pwmTapeImage.getData(instr);
            }

            /*Kontrola validity*/
            if (casData == null) {
                errorMessage = "CAS image data not created";
                Turgen.sync.unregisterProgress(this);
                Turgen.dlm.frmTurgen.getStatusObject().addFailedTapeImages();
                return;
            }

            /*Zapis dat do souboru, mame jmeno*/
            String fname = playListItem.outFile;
            
            /*Vynuceni vymazani souboru i bez vykricniku v prikazove radce*/
            boolean forceFileErase=false;
            
            /*Kdyz je jmeno prazdne a je povolena tvorba docasnych souboru a
             *je povolen postprocessing, tak se vytvori docasny soubor*/
            if (postProcessingEnabled==true && fname.equals("") && cfgTIOAutoCreateTempFile.getAsBoolean()==true) {
                
                fname=File.createTempFile("tscas", "tscas").getAbsolutePath();
                forceFileErase=true;
            }
            else {
                
                /*Pokud ma soubor priponu, inteligentne zmenit na .cas*/
                if (renameToCas == true) {
                    fname = Utils.changeFileExtension(fname, ".cas");
                } 
            }
            
            /*Vlastni zapis do souboru*/
            FileOutputStream fos = null;
            BufferedOutputStream bos = null;
            DataOutputStream dos = null;

            try {
                fos = new FileOutputStream(fname);
                bos = new BufferedOutputStream(fos);
                dos = new DataOutputStream(bos);

                for (int i = 0; i < casData.length; i++) {
                    dos.writeByte(casData[i]);
                }

                dos.close();

            } catch (Exception e) {
                try {
                    dos.close();
                } catch (Exception nce) {
                /*Umyslne prazdne*/
                }
                e.printStackTrace();
                errorMessage = Utils.getTitledExceptionMessage("Unable to write tape image: ",e);
                Turgen.sync.unregisterProgress(this);
                Turgen.dlm.frmTurgen.getStatusObject().addFailedTapeImages();
                return;
            }

            /*Soubor je zapsan, nyni bude nasledovat postprocessing*/
            String s1 = cfgTIOPostProcessingCommand.getAsString();

            if (s1!=null && !s1.equals("") && postProcessingEnabled == true) {

                try {

                    File f = new File(fname);
                    if (f.exists() && f.isFile()) {
                        f=f.getAbsoluteFile();
                        String outDir = f.getParent();
                        String outFileName = f.getName();
                        int j = outFileName.lastIndexOf('.');
                        String outFileNameNoExt = (j < 0) ? outFileName : outFileName.substring(0, j);

                        boolean dlt = forceFileErase;
                        if (s1.startsWith("!")) {
                            dlt = true;
                            s1 = s1.substring(1);
                        }
                        
                        s1 = Utils.replaceElements(s1, "%OD%", outDir);
                        s1 = Utils.replaceElements(s1, "%ODS%", outDir.concat(Turgen.sp));
                        s1 = Utils.replaceElements(s1, "%OFNE%", outFileName);
                        s1 = Utils.replaceElements(s1, "%OFN%", outFileNameNoExt);
                        
                        
                        String dsp = Turgen.sp+Turgen.sp;
                        s1=Utils.replaceElements(s1,dsp, Turgen.sp);

                        System.out.println("Tape image postprocessing: ");

                        String[] cmdArray = Utils.getCommandArrayFromCommandLine(s1);
                        
                        Utils.printCommandLine(cmdArray);

                        /*Prikazovy radek je pripraven*/
                        try {
                            postProcessingRun=true;
                            Process proc = Runtime.getRuntime().exec(cmdArray);
                            proc.waitFor();
                            if (dlt == true) {
                                f.delete();
                            }
                        } catch (InterruptedException ie) {
                        /*Muze nastat, neni problem*/
                        }
                        postProcessingRun=false;


                    }/*Soubor k postprocessingu je platny*/

                } catch (Exception e) {
                    errorMessage = "Tape image postprocessing failed";
                }
            }/*Postprocessing je vubec mozny*/

        } catch (Exception e) {
            errorMessage = Utils.getExceptionMessage(e);
        }
        
        
        /*Vsechno OK, odregistrovat*/
        Turgen.sync.unregisterProgress(this);
        Turgen.dlm.frmTurgen.getStatusObject().addGeneratedTapeImages();

    }

    public void cancelOperation(int cancelType) {
        this.cancelType=cancelType;
    }

    public int getStatusPercent() {
        return percent;
    }

    public String getStatusString() {
        if (postProcessingRun==false) {
            return "Tape image";
        }
        else {
            return "POSTPRO";
        }
    }

    public boolean isPartOfSequence() {
        return true;
    }

    public int getCancelledType() {
        return cancelType;
    }

    public String getOutputFile() {
        
        return "";
    }

    public String getInputFile() {
        if (playListItem!=null && playListItem.inFile!=null) {
            return playListItem.inFile; 
        }
        return "";

    }

    public String getErrorMessage() {
        return errorMessage;
    }
    
    synchronized public void unPause() {
        
    }

    public boolean isPausable() {
        return false;
    }

}
