
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.Reader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.InputStreamReader ;

import org.apache.tools.ant.Task;

/**   Resource files.
 *  All resource are store into resource files.   Resource files are created during build time, and packed all resources of same type
 *  into one file.  All resource files have a common header:
 *  <nbr of resource><offset of resource 1><offset of resource 2><offset of resource 3><offset of resource 4>....   
 *  Each header elts is 4 byte longs (int), so the header size is ((nbr of resource)+1)*4 
 *  
 *  Resource ID.
 *  Each resource is identified by an ID (and no longer by a string), which is the position of the resource in the file,
 *  and then the position of the resource in the array.   All Ids are static final member of the TextRscId class, which is generated 
 *  during the build.   For ex the RscId class will look like that:   
 *  
 *  public final class RscId
 *  {
 *      public final short Tx_rbLabel = 0 ;
 *      public final short Tx_lbLabel = 1 ;
 *      public final short Tx_mainViewTitle = 2 ;
 *      public final short Tx_welcomeMessage = 3 ;
 *      ......
 *  }
 *  
 *  it could be generate by the build from such resource files:
 *  text.english.resource
 *  rbLabel="ok"
 *  lbLabel="Quit"
 *  mainViewTitle="this is the main view"
 *  welcomeMessage="Hello world"
 *  
 *  Each resource file name is coded as the following: <type>.<name>.resource   The build shall automatically process any .resource files.
 */

/**
 * @author yishu
 *
 */
public abstract class ResourceToBinary extends Task
{
    protected static final String BEGIN_BRACKET = "{";
    protected static final String END_BRACKET = "}";
    protected static final String DECLARE = "public static final int ";
    protected static final String EQUAL = "=";
    protected static final String SEMICOLON = ";";
    protected static final String SLASHES = "// ";
    protected static final String FIRSTLINE = "public static final int NULL=-1;";
    protected static String CLASS_NAME;
    protected static String PREFIX;
    
    /** list of resolved values of resource keys */
    // private List<String> values;
    protected List values;
    /** list of resources keys */
    // private List<String> keys;
    protected List keys;
    /** file name */
    protected String fileName;
    
    /** JAVA file name */
    protected String javaFileName;

    /** destination directory */
    protected String toDir ;
    
    public ResourceToBinary()
    {
        values = new ArrayList();
        keys = new ArrayList();
    }
    
    // get the packeage path
    protected String PackagePath(String path)
    {
        String packPath = "";
        int strLen = path.length();

        // remove file name and replace / by .
        int lastSlashIndex = path.lastIndexOf("/") ;
        packPath = path.substring(0, lastSlashIndex) ;
        packPath=packPath.replace("/",".") ;
        
        packPath = "package " + packPath + SEMICOLON;
        return packPath;
    }
    
    // load the text from text resource file
    protected void loadText() throws Exception
    {
    	Reader in = new InputStreamReader(new FileInputStream(this.fileName + ".resource"), "UTF-8");
//    	String enc = ((InputStreamReader)in).getEncoding() ;
//    	System.out.println("enc:"+enc) ;
        BufferedReader br = new BufferedReader(in);
        String tmp = null;
        int index = -1;
        
        try
        {
            while(!(tmp = br.readLine()).equals("EOF"))
            {
                if (!(tmp.trim().startsWith("#")))
                {
                	index = tmp.indexOf("=");
                    if (index>-1) {
                    	String k = tmp.substring(0, index) ;
                    	String v = tmp.substring(index+1) ;
                    	keys.add(k);
                    	values.add(v);
//                    	System.out.println("k:"+k+" v:"+v) ;
                    }
                }
            }
        }
        catch(IOException e)
        {
            System.out.println(e.toString());
        }
    }
    
    // write binary data into stream
    protected abstract void writeBinary(DataOutputStream dos) throws IOException;
    
    protected void writeToJavaBinary(BufferedWriter bw) throws IOException
    {
        // create the resource index java class
        bw.write(PackagePath(javaFileName));         // write the packet name;
        bw.newLine();
        bw.write(CLASS_NAME);       // write the class name;
        bw.newLine();
        bw.write(BEGIN_BRACKET);     // write the begin bracket;
        bw.newLine();
        bw.write(FIRSTLINE);     // write the first id
    	bw.newLine();
    	
        // write the resource index declare
        for(int i = 0; i < keys.size(); i++)
        {	
        	String comment = SLASHES + (String) this.values.get(i);
        	bw.write(comment);   //write the comment
            bw.newLine();
                        
            String key = (String) this.keys.get(i);
            key = PREFIX +key;
            String id = DECLARE + key + EQUAL + i + SEMICOLON;
            bw.write(id);
            bw.newLine();           //write the declaration
        }
        bw.write(END_BRACKET);    // write the end bracket;
        bw.flush();
        
       this.DisplayMore();
    }
    
    protected void DisplayMore()
    {
    	 // parse file name and replace / by .
         int lastSlashIndex = this.javaFileName.lastIndexOf("/") ;
         String file = this.javaFileName.substring(lastSlashIndex+1);
         String packPath = this.javaFileName.substring(0, lastSlashIndex+1) ;
         
         if (this.fileName.indexOf("text")>0)    //output infomation
         {
         	System.out.println("successfully process file "+ this.fileName+", processed "+keys.size() +" text resources");
         	System.out.println("generate java file " + file + " in " + packPath);
         }
         else{
         	System.out.println("successfully process file "+ this.fileName+", processed "+keys.size() +" image resources");
         	System.out.println("generate java file " + file + " in " + packPath);
         }
    }
    
    // write the data into .bin file
    protected void writeToBinary()
    {
        FileOutputStream fos = null;
        DataOutputStream dos = null;
        FileWriter fw = null;
        BufferedWriter bw = null;
        
        try
        {
            fos = new FileOutputStream(this.fileName + ".bin");
            dos = new DataOutputStream(fos);
            
            String destFile = toDir +"/"+ javaFileName ;
            fw = new FileWriter(destFile);
            bw = new BufferedWriter(fw);

            writeBinary(dos);
            writeToJavaBinary(bw);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (fos != null)
                    fos.close();
            }
            catch (IOException e)
            {
                System.out.println(e.toString() + " error for .bin file");
            }
            try
            {
                if (dos != null)
                    dos.close();
            }
            catch (IOException e)
            {
                System.out.println(e.toString() + " error for .bin file");
            }
            try
            {
                if (fw != null)
                    fw.close();
            }
            catch (IOException e)
            {
                System.out.println(e.toString() + " error for .java file");
            }
            try
            {
                if (bw != null)
                    bw.close();
            }
            catch (IOException e)
            {
                System.out.println(e.toString() + " error for .java file");
            }
        }
    }
    
    public String getFileName()
    {
        return fileName;
    }

    public void setFileName(String fileName)
    {
        this.fileName = fileName;
    }
    
    public String getTodir()
    {
        return toDir ;
    }

    public void setTodir(String todir)
    {
        toDir = todir;
    }
    
    public void setJavaFileName(String javaFileName)
    {
        this.javaFileName = javaFileName;
    }
    
    public String getJavaFileName()
    {
        return javaFileName;
    }

}
