package turgen;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import turgen.config.AbstractConfigEntry;
import turgen.config.ConfigDialog;
import turgen.config.ConfigEntryListener;
import turgen.config.StringConfigEntry;
import turgen.dtb.StatisticsDialog;
import turgen.tapeimageextractor.ExtractorDialog;
import turgen.wizard.WizardDialog;

/**
 * Centralized Frame and Dialog handling
 */
public class DialogManager implements ConfigEntryListener {
    
    /**Main window*/
    public TurgenFrame frmTurgen;

    /**Dialog used for editing playlist items*/
    PlayListItemDialog dlgRecord;
    
    /**Frame for DOS 2 binaries merging*/
    private MergerDialog dlgMergeBinary;

    /**Dialog for configuration*/
    ConfigDialog dlgConfig;
    
    /**Frame for turbo decoder*/
    DecoderFrame frmDecoder;

    /**Statistics dialog*/
    public StatisticsDialog dlgStatistics;

    /**Wizard dialog*/
    private WizardDialog dlgWizard;
    
    /**Basic to binary embedder*/
    private EmbedBasicDialog dlgEmbedBasic;
    
    /**Tape image extractor*/
    private ExtractorDialog dlgExtractor;
    
   
    /**Configuration of look and feel*/
    StringConfigEntry cfgLookAndFeel;
    
    /**Last look and feel set*/
    private String lastLookAndFeel="";

    private UIPersistor[] residentWindowArray;
    
    
    private final HashMap uiPersistenceMap;

    
    private DialogManager() {
        /*Look and feel*/
        uiPersistenceMap = new HashMap();
        String[] plafs = new String[6];
        plafs[0]="javax.swing.plaf.metal.MetalLookAndFeel";
        plafs[1]="com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
        plafs[2]="com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
        plafs[3]="com.sun.java.swing.plaf.motif.MotifLookAndFeel";
        plafs[4]="com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
        plafs[5]="com.sun.java.swing.plaf.mac.MacLookAndFeel";
        cfgLookAndFeel = new StringConfigEntry("lookAndFeel","GUI Look and feel","",plafs,true);
        Turgen.cfcTurgen.addEntry(cfgLookAndFeel);
    }
    
    public static DialogManager getInstance() {
        return new DialogManager();
    }
    
    /** Create all dialogs*/
    public void initDialogs() {

        /*Initialize resident dialogs*/
        frmTurgen=new TurgenFrame();
        dlgRecord = new PlayListItemDialog(frmTurgen);
        dlgConfig = new ConfigDialog(frmTurgen);
        dlgStatistics = new StatisticsDialog(dlgRecord);
        
        residentWindowArray = new UIPersistor[4];
        residentWindowArray[0]=frmTurgen;
        residentWindowArray[1]=dlgRecord;
        residentWindowArray[2]=dlgConfig;
        residentWindowArray[3]=dlgStatistics;

        
        /*Initialize transient dialogs*/
        dlgWizard = null;
        dlgEmbedBasic = null;
        dlgExtractor = null;
        dlgMergeBinary = null;
        
        /*Initialize transient frames*/
        frmDecoder = null;

        /*Look and feel changes*/
        cfgLookAndFeel.setListener(this);
        
    }
    
    /** Restore frame/dialog bounds. If restoration not possible, use
     *  defaults
     */
    void loadBounds() {
        
        FileInputStream fis;
        DataInputStream dis;
        ObjectInputStream ois=null;
        
        /*Try to load the bounds*/
        try {

            fis = new FileInputStream(Turgen.configDir+"winlayout.ser");
            dis = new DataInputStream(fis);
            
            int numObjects = dis.readInt();
            
            for(int i=0;i<numObjects;i++) {
                    String key = dis.readUTF();
                    int objectLength = dis.readInt();
                    byte[] objectBytes = new byte[objectLength];
                    dis.read(objectBytes);
                    
                    try {
                        ByteArrayInputStream bais = new ByteArrayInputStream(objectBytes);
                        ois = new ObjectInputStream(bais);
                        Object value = ois.readObject();
                        uiPersistenceMap.put(key,value);
                        ois.close();
                    }
            
                    catch(Exception ex) {
                        ex.printStackTrace();
                        ois.close();
                    }
            }
            
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        
        /*Now we have the persistence map*/
        finally {
            
            /*Resident windows*/
            UIPersistor p;
            for(int i=0;i<residentWindowArray.length;i++) {
                p=residentWindowArray[i];
                if (uiPersistenceMap.containsKey(p.getPersistenceId())) {
                    try {
                        p.setPersistenceData(((Object[])(uiPersistenceMap.get(p.getPersistenceId()))));
                    }
                    catch (Exception e) {
                        p.setPersistenceDefaults();
                        uiPersistenceMap.put(p.getPersistenceId(), p.getPersistenceData());
                    }
                }
                else {
                    p.setPersistenceDefaults();
                    uiPersistenceMap.put(p.getPersistenceId(), p.getPersistenceData());
                }
            }
            /*Transient windows are handled separately*/
            
        }


        
    }
    /** Pokusi se ulozit pozice dialogu do souboru*/
    void saveBounds() {

        FileOutputStream fos;
        DataOutputStream dos;
        
       closeTransientFrames();
        
        try {
            fos = new FileOutputStream(Turgen.configDir+"winlayout.ser");
            dos = new DataOutputStream(fos);

            /*First number of objects*/
            dos.writeInt(uiPersistenceMap.size());
            
            /*Flush persistence data of resident windows*/
            for(int i=0;i<residentWindowArray.length;i++) {
                uiPersistenceMap.put(residentWindowArray[i].getPersistenceId(), residentWindowArray[i].getPersistenceData());
            }
            
            Set keySet = uiPersistenceMap.keySet();
            Iterator it = keySet.iterator();
            
            while(it.hasNext()) {
                
                String key = (String)it.next();
                Object value = uiPersistenceMap.get(key);
                
                /*Temporary stream*/
                ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
                ObjectOutputStream toos = new ObjectOutputStream(baos);
                toos.writeObject(value);
                toos.flush();
                toos.close();
                byte[] objectBytes = baos.toByteArray();
                
                /*Write key, length and value*/
                dos.writeUTF(key);
                dos.writeInt(objectBytes.length);
                dos.write(objectBytes);
            }
            
            
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        
    }
    
    /**Center container 
     * @param c Container to center*/
    public static void centerContainer(Container c) {
        Dimension _d =Toolkit.getDefaultToolkit().getScreenSize();
    	int _x,_y;
    	_x = (_d.width-c.getBounds().width)/2;   
	_y = (_d.height-c.getBounds().height)/2;  
	c.setLocation(_x,_y);
    }
    
    
    public void onConfigEntryChange(AbstractConfigEntry entry) {
        final AbstractConfigEntry ace = entry;
        if (SwingUtilities.isEventDispatchThread()) {
            try {
                SwingUtilities.invokeLater(new Runnable() {
                   
                    public void run() {
                        onConfigEntryChangeImpl(ace);
                    }
                });
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
        else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                   
                    public void run() {
                        onConfigEntryChangeImpl(ace);
                    }
                });
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public void onConfigEntryChangeImpl(AbstractConfigEntry entry)  {
        
        /*Pick class name and check if it is blank*/
        StringConfigEntry sce = (StringConfigEntry)entry;
        String plafClass = sce.getAsString();
        if (sce.isBlank() == true) {
            plafClass = System.getProperty("swing.defaultlaf");
            if (plafClass==null) return;
        }
        
        /*Change look and feel*/
        if (!lastLookAndFeel.equals(plafClass)) {
            lastLookAndFeel = plafClass;

            try {
                UIManager.setLookAndFeel(plafClass);
                SwingUtilities.updateComponentTreeUI(frmTurgen);
                SwingUtilities.updateComponentTreeUI(dlgRecord);
                SwingUtilities.updateComponentTreeUI(dlgConfig);
                SwingUtilities.updateComponentTreeUI(dlgStatistics);
                frmTurgen.updateFileDialogUI();
                dlgRecord.updateFileDialogUI();
                updateTransientDialogsUI();
                updateTransientFramesUI();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }
    
    private void updateTransientDialogsUI() {
        if (dlgMergeBinary!=null) {
            SwingUtilities.updateComponentTreeUI(dlgMergeBinary); 
            dlgMergeBinary.updateFileDialogUI();
        }
        if (dlgEmbedBasic!=null) {
            SwingUtilities.updateComponentTreeUI(dlgEmbedBasic);
            dlgEmbedBasic.updateFileDialogUI();
        }
        if (dlgExtractor!=null) {
            SwingUtilities.updateComponentTreeUI(dlgExtractor);
            dlgExtractor.updateFileDialogUI();
        }
        if (dlgWizard!=null) {
            SwingUtilities.updateComponentTreeUI(dlgWizard);
            dlgWizard.updateFileDialogUI();
        }
    }
    
    private void updateTransientFramesUI() {
        if (frmDecoder !=null) {
            SwingUtilities.updateComponentTreeUI(frmDecoder);
            frmDecoder.updateFileDialogUI();
        }
   }
    
    public void setMergeTransientDialogVisible() {

        if (dlgMergeBinary == null) {
            dlgMergeBinary = new MergerDialog();
            getPersistenceForTransientDialog(dlgMergeBinary);
        }
        dlgMergeBinary.setVisible(true);

        uiPersistenceMap.put(dlgMergeBinary.getPersistenceId(), dlgMergeBinary.getPersistenceData());
        dlgMergeBinary = null;

    }

    public void setEmbedBasicTransientDialogVisible() {

        if (dlgEmbedBasic == null) {
            dlgEmbedBasic = new EmbedBasicDialog();
            getPersistenceForTransientDialog(dlgEmbedBasic);
        }
        dlgEmbedBasic.setVisible(true);

        uiPersistenceMap.put(dlgEmbedBasic.getPersistenceId(), dlgEmbedBasic.getPersistenceData());
        dlgEmbedBasic = null;

    }

    public void setExtractorTransientDialogVisible() {
        if (dlgExtractor == null) {
            dlgExtractor = new ExtractorDialog();
            getPersistenceForTransientDialog(dlgExtractor);
        }
        dlgExtractor.setVisible(true);
        uiPersistenceMap.put(dlgExtractor.getPersistenceId(), dlgExtractor.getPersistenceData());
        dlgExtractor = null;

    }

    public void setWizardTransientDialogVisible(boolean visible) {

        if (dlgWizard == null) {
            dlgWizard = new WizardDialog();
            getPersistenceForTransientDialog(dlgWizard);
        }
        dlgWizard.setVisible(true);

        uiPersistenceMap.put(dlgWizard.getPersistenceId(), dlgWizard.getPersistenceData());
        dlgWizard = null;

    }

    public void setDecoderTransientFrameVisible(boolean visible) {

        if (visible == true) {
            if (frmDecoder == null) {
                frmDecoder = new DecoderFrame();
                getPersistenceForTransientDialog(frmDecoder);
            }
            frmDecoder.setVisible(true);

        }
        else {
            if (frmDecoder!=null) {
                uiPersistenceMap.put(frmDecoder.getPersistenceId(), frmDecoder.getPersistenceData());
                frmDecoder.setVisible(false);
                frmDecoder.dispose();
                frmDecoder = null;
            }
        }
    }

    private void getPersistenceForTransientDialog(UIPersistor p) {
        if (uiPersistenceMap.containsKey(p.getPersistenceId())) {
            try {
                p.setPersistenceData(((Object[]) (uiPersistenceMap.get(p.getPersistenceId()))));
            } catch (Exception e) {
                e.printStackTrace();
                p.setPersistenceDefaults();
                uiPersistenceMap.put(p.getPersistenceId(), p.getPersistenceData());
            }
        }
        else {
            p.setPersistenceDefaults();
            uiPersistenceMap.put(p.getPersistenceId(), p.getPersistenceData());
        }
    }

    private void closeTransientFrames() {
        setDecoderTransientFrameVisible(false);
    }

}
