package JEM.Utils;
/**
 * ReadGui
 *
 * Used to decompile a gui file.
 *
 * @author  Jere McDevitt
 *
 */
import marimba.io.*;
import marimba.gui.*;
import marimba.persist.*;
import marimba.text.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.*;

public class ReadGui
{
    static public final String strVERSION = "Copyright 1996, Jere E. McDevitt  Ver. 1.1.1";
    public Presentation m_prPresentation = null;
    Hashtable m_htNames = new Hashtable();
    Hashtable m_htTheObjectNames = null;
    Vector m_vWidgetNames = new Vector();
    String tabIndent = null;
    /*
     * Modify this variable to reflect a method call available
     * to all widgets that takes a file name and returns 
     * a fully qualified name for the source.
     * 
     * This can be a function call or a path.  If it is a 
     * function call, enter it like:
     * 
     * m_strSrcFunction = "m_pTheFrame.getURLString("%");"
     * 
     * The % is the place holder overwritten by the end of the
     * string.
     * 
     * If you want the string as is, set m_strSourceFunction to null;
     * 
     * If you just want a path, set:
     *  m_strSrcFunction = "file://d:/marimba/bongo/project/readgui/resource/";
     * 
     * the trailing / is required as the name from the gui is ONLY the last
     * portion of the string.
     * 
     * Finally, here is an example of a function you could use.
     * 
     * e.g.
     * String getURLString(String filename)
     * {
     *    URL theUrl = null;
     *    try
     *    {
     *       theUrl = new URL(getDocumentBase(),filename);
     *    }
     *    catch( MalformedURLException ex)
     *    {
     *       System.out.println(ex.getMessage());
     *       return "";
     *    }
     *    if( theUrl != null )
     *       return theUrl.toString();
     *    return "";
     * }
     */ 
    String m_strSrcFunction = null;

    /**
     * Constructor.
      * 
      * @param file name of the .gui file.
     */
    public ReadGui(String file, String srcfunc)
    {
        try
        {
            URL theURL = new URL("file","",file);
            m_prPresentation = Presentation.getPresentation(theURL);
        }
        catch (MalformedURLException e)
        {
            System.out.println("Failed to load presentation");
            e.printStackTrace();
            System.exit(-1);
        }
        m_strSrcFunction = srcfunc;
        
   }


    /**
     * Checks to see if the .gui file loaded correctly.
     */
    boolean presLoaded()
   {
        if( m_prPresentation != null )
        return true;
      return false;
   }
   
    /**
     * Adds the widget name to the vector.
     */
   public void addConstructor(String compname )
   {
        m_vWidgetNames.addElement(compname );
   }
    
    /**
     * Writes out the declaration for all of the components.
     */
    public void writeConstructors(FastOutputStream ps)
    {
        for(Enumeration v = m_vWidgetNames.elements();v.hasMoreElements();)
        {
            String str = (String)v.nextElement();
            if( str != null && !str.equals("") )
            {
                StringTokenizer stk = new StringTokenizer(str,"\n");
                while( stk.hasMoreTokens() )
                {
                    ps.println(tabIndent + stk.nextToken() );
                }
            }
        }
    }
   
    /**
     * Generates a unique name for a given component type.
     */
    String getNextName(String endOf)
    {
        Integer intVal = (Integer)m_htNames.get(endOf);
        int val = 1;
        if( intVal != null )
        {
            val = intVal.intValue() + 1;
        }
        m_htNames.remove(endOf);
        m_htNames.put(endOf,new Integer(val));
        return "m_dt"+endOf+"_" + Integer.toString( val );
    }
   
    /**
     * Returns the string representation of the class type.  Used
     * as the class name.
     */
    String getTypeName(Widget w)
    {
        String endOf = w.getWidgetClass().getName();
        int index = endOf.lastIndexOf('.');
        if( index != -1 )
          endOf = endOf.substring(index+1);

        return endOf;
    }
    
   
    /**
     * This routine determines the type of the widget.  To add
     * types, be certain to place them above any ancestor classes
     * so the correct class is detected.
     */
    
    public void buildObjectNames(Widget w)
    {
        String endOf = getTypeName( w);
        String name = w.name;
        if( name == null || name.equals(""))
        {
            name = getNextName(endOf);
        }
        else
        {
            Integer theInt = (Integer)m_htNames.get(name);
            int val = 1;
            if( theInt != null )
            {
                val = theInt.intValue() + 1;
            }
            m_htNames.remove(name);
            m_htNames.put(name, new Integer(val));
            if( val != 1 )
              name = name + Integer.toString(val);
            name = name.replace('-','_');
        }       
        m_htTheObjectNames.put(w, name );
        if( w.nwidgets != 0 && w.widgets != null )
        {
            for( int i = 0; i < w.nwidgets; i++)
            {
                buildObjectNames( w.widgets[i] );
            }
        }       
    }
    
    /**
     * This routine generates a unique name (or reads the given name)
     * for a widget and determines it's type to begin the dump
     * procedure.
     */
    String dumpWidget(String parent, Widget w,FastOutputStream ps, Widget pw)
    {
        if( w instanceof TextView ||
            w instanceof DropDownTextBoxWidget ||
            w instanceof SpinBoxTextWidget ||
            (w instanceof ListWidget && pw instanceof ListBoxWidget) ||
		    (w instanceof ScrollbarWidget && pw instanceof TextWidget ))
          return null;
        
        
        String endOf = getTypeName(w);
        String name = (String)m_htTheObjectNames.get(w);
        ReadGuiPropertyList rgpl = new ReadGuiPropertyList();
        
        w.getProperties(rgpl);
        rgpl.dumpProperties(ps, tabIndent, m_htTheObjectNames, w, m_strSrcFunction);
        ps.println(tabIndent+name+".setProperties(rgpl);");
        
        addConstructor("\t" + endOf + " " + name + " = new " + endOf + "();");
        ps.println(tabIndent + name + ".setName(\""+name+"\");");                   
        if( !(w instanceof PageWidget) )
            ps.println(tabIndent + parent + ".add(" + name + ");");                    
        else
            ps.println(tabIndent + parent + ".addPage(" + name + ");");
       
        ps.println("\n");
        return name;
        
   }

    /**
     * This is the start routine for dumping a widget.  
     * It dumps the given widget then cycles through the
     * children.
     */
    
    synchronized public void dumpComponent(String parent, Widget w, FastOutputStream ps, Widget pw)
    {
        String name = dumpWidget(parent,w,ps, pw);
        if(name != null )
        {
            for( int i = 0; i < w.nwidgets; i++)
            {
                dumpComponent(name,w.widgets[i], ps, w);
            }
        }
       
   }
            
   /**
    * Main dump routine.
    */
    void dumpPresentation(FastOutputStream ps, String fname, String guiname, boolean newFile)
    {
        int index = fname.indexOf('.');
        String classname = null;
        
        if( index != -1 )
            classname = fname.substring(0,index-1);
        else
            classname = fname;

        if( newFile )
        {
        
            ps.println("import marimba.gui.*;");
            ps.println("import marimba.text.*;");
            ps.println("import java.awt.*;\n");
            ps.println("public class " + classname + " extends Presentation");
            ps.println("{");
            tabIndent = "\t";
            ps.println(tabIndent+"public " + classname + "()");
            ps.println(tabIndent+"{");
            ps.println(tabIndent+"\tsuper();");
            ps.println(tabIndent+"}");
        }

        tabIndent= "\t";
        ps.println(tabIndent+"//{{ Will be overwritten by ReadGui");
        ps.println(tabIndent+"public void init()");
        ps.println(tabIndent+"{");
        tabIndent = "\t\t";
        ps.println(tabIndent + "String scriptStr = null;");
        ps.println(tabIndent + "byte[] ba1 = null;");
        ps.println(tabIndent + "byte[] ba2 = null;");
        ps.println(tabIndent + "Object[] oa = null;");
        ps.println(tabIndent + "ReadGuiPropertyList rgpl = new ReadGuiPropertyList();");
       
        m_htTheObjectNames = new Hashtable();
        buildObjectNames(m_prPresentation);
       
        addConstructor("\tPresentation " + m_htTheObjectNames.get(m_prPresentation) + " = this; ");    
        ReadGuiPropertyList rgpl = new ReadGuiPropertyList();
        m_prPresentation.getProperties(rgpl);
        rgpl.dumpProperties(ps, tabIndent, m_htTheObjectNames, m_prPresentation, m_strSrcFunction );
        ps.println(tabIndent+"setProperties(rgpl);");
        ps.println("\n");

        try
        {
            if( m_prPresentation.nwidgets != 0 && m_prPresentation.widgets != null )
            {
                for( int i = 0; i < m_prPresentation.nwidgets; i++)
                    dumpComponent("this", m_prPresentation.widgets[i], ps, m_prPresentation);   
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        ps.println(tabIndent+"additionalInit();"); 
        tabIndent = "\t";
        ps.println(tabIndent+"}\n");
        ps.println(tabIndent+"/*");
        ps.println(tabIndent+" * Defined in GUI file.");
        ps.println(tabIndent+" */");
        
        writeConstructors(ps);
        ps.println(tabIndent+"//}}Add additional definitions after here.");
        if( newFile )
        {
            ps.println(tabIndent + "public void additionalInit()");
            ps.println(tabIndent + "{\n" + tabIndent + "\t/*");
            ps.println(tabIndent + "\t   add any initialization code that shouldn't");
            ps.println(tabIndent + "\t   be overwritten here.");
            ps.println(tabIndent + "\t*/");
            ps.println(tabIndent + "}");
            ps.println("}");
        }
        
    }

	static void usage()
	{
   	System.out.println("ReadGui " + strVERSION);
      System.out.println("usage: ReadGui [-sf \"\"]  -i fname.gui -o MyClassName");
      System.out.println("-sf  SourceFunction - used for generating call to load images/audio clips");
      System.out.println("-i   fname.gui      - Input file.  Must have .GUI extension");
      System.out.println("-o   MyClassName    - name of class file to write to.");
		System.out.println("-h   help           - this display.");
      System.exit(-1);
	}

   static String replace(String line, String from, String to)
	{
		int index;
		while( (index = line.indexOf(from)) != -1 )
		{
			String retval = line.substring(0,index) + to + line.substring(index+from.length());
			line = retval;			
		}
		return line;
	}
	
   /**
    * Main.
    */
	public static void main(String args[])
   {
   	FastOutputStream ps = null;
      FastInputStream pi = null;
      FastInputStream cmts = null;
      String guiname = null;
      String fname = null;    
      String classname = null;
      String srcfunc = null;
      int i = 0;
		int state = 0;
      try
		{
			for( i = 0; i < args.length; i++)
			{
				if( args[i].equals("-i") )
					state = 1;
				else if( args[i].equals("-o") )
					state = 2;
				else if( args[i].equals("-sf") )
					state = 3;
				else if( args[i].equals("-h") )
				{
					usage();
					state = 0;
				}
				else
				{
					switch( state )
				  	{
					  	case 0:
		  					System.out.println("Missing argument code.");
						  	System.exit(-1);
						case 1:
							guiname = args[i];
							break;
						case 2:
							fname = args[i];
							break;
						case 3:
							srcfunc = args[i];
							break;
					}
				}
			}
		}
      catch(ArrayIndexOutOfBoundsException ex)
      {
      	System.out.println("Insufficient arguments");
         System.exit(-1);
      }

		if( fname == null )
		{
			if( guiname != null )
			{
				int index = guiname.indexOf(".gui") ;
				if( index == -1)
				{
					fname = guiname;
					guiname = guiname + ".gui";
				}
				else
				{
					fname = guiname.substring(0,index);
				}
				index = fname.lastIndexOf(File.separator);
				if( index != -1 )
				{
					fname = fname.substring(index+1);
				}
			}
		}
		 
      if( guiname == null )
      {
      	System.out.println("Missing gui name");
         System.exit(-1);
      }
		
		if( !guiname.endsWith(".gui") )
		  guiname = guiname + ".gui";
        
      ReadGui rg = new ReadGui(guiname, srcfunc);             
      if( rg.presLoaded() == false )
      {
      	System.out.println("GUI: " + guiname + " not found.");
         System.exit(-1);
      }
        
      if( fname.endsWith(".java") )
      {
      	int index = fname.lastIndexOf('.');
         classname = fname.substring(0,index-1);
      }
      else
      {
      	classname = fname;
         fname = fname + ".java";
      }
      System.out.println("Processing " + guiname + " into " + classname + ".java");       
        
        
		try
      {
      	ps = new FastOutputStream("readgui.temp");
      }
      catch(IOException ex)
      {
      	System.out.println("Unable to open temporary file:"+ex.getMessage());
         System.exit(-1);
      }
        
      try
      {
      	cmts = new FastInputStream("readgui.comments");
      }
      catch(IOException ex)
      {
      }
        
      try
      {
      	pi = new FastInputStream(fname);
      }
      catch(FileNotFoundException ex)
      {
      	pi = null;
      }
      catch(IOException ex)
      {
      	System.out.println("Unable to open existing file:"+ex.getMessage());
         System.exit(-1);
      }

      if( pi != null )
      {
      	String line;
         while( (line = pi.readLine()) != null )
         {
         	if( line.indexOf("//{{") != -1)
            	break;
            ps.println(line);
         }
            
      }
      else
      {
      	ps.println("/*");
         ps.println(" *  Produced by ReadGui from GUI file: " + guiname);
         ps.println(" *\n * Version " + strVERSION);
         ps.println(" *\n */\n");

         if( cmts != null )
         {
         	String line;
            while( (line = cmts.readLine()) != null )
            {
					line = replace(line, "%CLASSNAME%", classname);
					line = replace(line, "%FILENAME%", fname );
					line = replace(line, "%GUINAME%", guiname );
            	ps.println(line);
            }
         }
		}
        
                
      rg.dumpPresentation(ps, classname, guiname, pi == null);
		if( pi != null )
      {
      	String line;
         boolean doWrites = false;
         while( (line = pi.readLine()) != null )
         {
         	if( doWrites)
            	ps.println(line);               
            if( line.indexOf("//}}") !=-1 )
            	doWrites = true;
         }
      }
        
 		try
      {
      	ps.flush();
         ps.close();
         if( pi != null )
         	pi.close();
         if( cmts != null )
            cmts.close();
      }
     	catch(IOException ex)
      {
      	System.out.println("Closing file:" + ex.getMessage());
         ex.printStackTrace();
      }
        
      /**
       * Ok.  Now that the data is in the readgui.temp file it is time
       * to rename the file.
       */
      File theFile = new File( fname );
      if( theFile != null )
      {
      	theFile.delete();
      }
        
      theFile = new File("readgui.temp");
      if( theFile.renameTo(new File(fname)) == false )
      {
      	System.out.println("Failed to rename temporary file.");
      }
        
      System.exit(0);
	}
}
