/*
 * Copyright
 *   2007 axYus - www.axyus.com
 *   2007 N.Le Corre - nicolas.lecorre@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.cp.buildtools;

import java.io.File;
import java.io.FileInputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.Properties;

import jonelo.jacksum.algorithm.AbstractChecksum;
import jonelo.jacksum.algorithm.MD;


public class Gen {
    private static StringBuffer xemeliosUpdates = new StringBuffer(), configUpdates = new StringBuffer(), featureUpdates = new StringBuffer(), unknownUpdates = new StringBuffer();
    
    public static String BASE_UPDATE_URL  ="http://www.xemelios.org/updates33/";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String initDir = null, outputFileName=null;
                if(args.length>0) initDir=args[0];
                if(args.length>1) outputFileName=args[1];
                if(args.length>2) BASE_UPDATE_URL = args[2];
		if (initDir==null || "".equals(initDir)) {
			System.out.println("usage :");
			System.out.println("\t fr.gouv.finances.cp.buildtools.Gen <DIR>");
                        System.out.println("\t ou <DIR> est le chemin ou se trouvent les composants");
			System.exit(1);
		}
		
		File fInitDir = new File (initDir);
		if (!fInitDir.isDirectory()) {
			System.out.println(initDir+" n'est pas un répertoire valide");
			System.exit(1);
		}
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String laDate = sdf.format (GregorianCalendar.getInstance().getTime());
		
		// le fichier final
		StringBuffer update = new StringBuffer();
		update.append ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		update.append ("<xemelios-update xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"update.xsd\">\n");
		update.append ("\t<release v=\"PUT HERE FILE RELEASE\" date=\"").append (laDate).append("\"/>\n");
		update.append ("\t<original-location>").append(BASE_UPDATE_URL).append("update.xml</original-location>\n");
//		update.append ("<xemelios-updates>\n");
		
		// parcours des répertoires de premier niveau. Ce sont les composants à intégrer
		System.out.println("Processing components ...");
		for (File component:fInitDir.listFiles()) {
			// on ne considère que les répertoires et on ignore les répertoires "." et ".."
			if (component.isDirectory() && !".".equals(component.getName()) && !"..".equals(component.getName())) {
				System.out.println ("\tprocessing component : "+component.getName());
				
				// versions du composant
				for (File version:component.listFiles()) {
					// on ne considère que les répertoires et on ignore les répertoires "." et ".."
					if (version.isDirectory() && !".".equals(version.getName()) && !"..".equals(version.getName())) {
						System.out.println ("\t\tprocessing version : "+version.getName());
                                                processVersion(version,component.getName(),laDate);
                                        }
				}
			}
		}
                if(xemeliosUpdates.length()>0) {
                    update.append("\t<xemelios-updates>\n");
                    update.append(xemeliosUpdates.toString());
                    update.append("\t</xemelios-updates>\n");
                } else {
                    update.append("\t<xemelios-update />\n");
                }
                if(configUpdates.length()>0) {
                    update.append("\t<config-updates>\n");
                    update.append(configUpdates.toString());
                    update.append("\t</config-updates>\n");
                } else {
                    update.append("\t<config-updates />\n");
                }
                if(featureUpdates.length()>0) {
                    update.append("\t<features-updates>\n");
                    update.append(featureUpdates.toString());
                    update.append("\t</features-updates>\n");
                } else {
                    update.append("\t<features-updates />\n");
                }
                if(unknownUpdates.length()>0) {
                    update.append("\t<unknown-updates>\n");
                    update.append(unknownUpdates.toString());
                    update.append("\t</unknown-updates>\n");
                }

                update.append("\n\t<!-- foreign-sites>\n\t\t<site name=\"xemelios-main\">").append(BASE_UPDATE_URL).append("update.xml</site>\n\t</foreign-sites -->\n\n");

		update.append ("</xemelios-update>\n");
		System.out.println("Proccessing done.");
                if(outputFileName!=null) {
                    File of = new File(new File(initDir),outputFileName);
                    try {
                        PrintStream ps = new PrintStream(of,"UTF-8");
                        ps.print(update.toString());
                        ps.flush(); ps.close();
                    } catch(Throwable t) {
                        t.printStackTrace();
                    }
                } else {
                    System.out.println(update.toString());
                }
	}
        
        private static void processVersion(File version, String componentName,String laDate) {
            Properties props = new Properties();
//            if("rapport".equals(componentName)) {
//                System.gc();
//            }
            File propFile = new File(version,"component.properties");
            if(propFile.exists()) {
                try {
                    props.load(new FileInputStream(propFile));
                } catch(Throwable t) {
                    // ignored
                }
            }
            StringBuffer buff = null;
            if("xemelios-updates".equals(props.getProperty("type"))) buff = xemeliosUpdates;
            else if("config-updates".equals(props.getProperty("type"))) buff = configUpdates;
            else if("features-updates".equals(props.getProperty("type"))) buff = featureUpdates;
            else buff = unknownUpdates;
            buff.append ("\t\t<component cid=\"").append(componentName).append ("\">\n");
            buff.append ("\t\t\t<release v=\"").append (version.getName()).append ("\" date=\"").append (laDate).append ("\"/>\n");
            buff.append ("\t\t\t<description>").append(props.getProperty("description","PUT HERE COMPONENT DESCRIPTION")).append("</description>\n");
            String requires = props.getProperty("requires");
            if(requires!=null && requires.length()>0) {
                buff.append("\t\t\t<requires>\n");
                String comps[] = requires.split(";");
                for(String comp:comps) {
                    String[] compInfo = comp.split(",");
                    buff.append("\t\t\t\t<component-ref cid=\"").append(compInfo.length>=0?compInfo[0]:"PUT HERE COMPONENT NAME").append("\" version=\"").append(compInfo.length>=1?compInfo[1]:"PUT HERE COMPONENT VERSION").append("\"/>\n");
                }
                buff.append("\t\t\t</requires>\n");
            }
            buff.append ("\t\t\t<files root=\"").append(BASE_UPDATE_URL).append (componentName).append ("/").append(version.getName()).append("\">\n");
            // fichiers de la version
            for (File fic:version.listFiles()) {
                // on ne considère que les fichiers
		if (fic.isFile() && !"component.properties".equals(fic.getName())) {
                    System.out.println ("\t\t\tprocessing file : "+fic.getName());
                    String _md5 = "";
                    try {
                        AbstractChecksum checksum = new MD("MD5");
                        checksum.readFile(fic.getAbsolutePath());
                        _md5 = checksum.getFormattedValue();
                    } catch (Exception e) {
                        System.out.println ("Impossible de calculer le md5 du fichier : "+fic.getAbsolutePath());
                    }
                    String fName = fic.getName();
                    String dest = props.getProperty("base.dest","PUT HERE DESTINATION");
                    if(props.getProperty(fName+".dest")!=null) dest = props.getProperty(fName+".dest");
                    buff.append ("\t\t\t\t<file name=\"").append(fName).append("\" source=\"").append(fName).append ("\" dest=\"").append(dest).append("\" md5=\"").append (_md5).append ("\"/>\n");
                } else if(fic.isDirectory()) {
                    addSubDirectory(fic,fic.getName()+"/",props.getProperty("base.dest","PUT HERE DESTINATION"),buff);
//                } else if(fic.getName().equals("component.properties")) {
//                    fic.delete();
                }
            }
            // add here deletes
            String deletes = props.getProperty("deletes");
            if(deletes!=null) {
                String[] toDelete = deletes.split(",");
                for(String s:toDelete) {
                    buff.append("\t\t\t\t<delete name=\"").append(s).append("\"/>\n");
                }
            }
            buff.append("\t\t\t</files>\n");
            if(props.getProperty("configuration")!=null) {
                buff.append("\t\t\t<configuration class=\"").append(props.getProperty("configuration")).append("\"/>\n");
            }
            buff.append("\t\t</component>\n");
        }
        
        private static void addSubDirectory(File dir,String dirName, String destBase, StringBuffer buff) {
            if(dir==null) throw new RuntimeException("dir is null");
            if(!dir.isDirectory()) throw new RuntimeException(dir.getAbsolutePath()+" is not a directory");
            for (File fic:dir.listFiles()) {
                // on ne considère que les fichiers
		if (fic.isFile()) {
                    System.out.println ("\t\t\tprocessing file : "+fic.getName());
                    String _md5 = "";
                    try {
                        AbstractChecksum checksum = new MD("MD5");
                        checksum.readFile(fic.getAbsolutePath());
                        _md5 = checksum.getFormattedValue();
                    } catch (Exception e) {
                        System.out.println ("Impossible de calculer le md5 du fichier : "+fic.getAbsolutePath());
                    }
                    buff.append ("\t\t\t\t<file name=\"").append(fic.getName()).append("\" source=\"").append(dirName).append (fic.getName()).append ("\" dest=\"").append(destBase).append(dirName).append("\" md5=\"").append (_md5).append ("\"/>\n");
                } else {
                    addSubDirectory(fic,dirName+fic.getName()+"/",destBase,buff);
                }
            }
            
        }

}
