content: /**
   * Copyright 2009 DFKI GmbH.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * This file is part of MARY TTS.
   * <p/>
   * MARY TTS 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, version 3 of the License.
   * <p/>
   * This program 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.
   * <p/>
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package marytts.tools.install;
  
  /**
   * @author marc
   */
  public class CreateComponentXML {
      public static final String PROPERTY_XML_FOLDER = "mary.componentXML.folder";
      public static final String PROPERTY_XML_OUTPUTFILE = "mary.componentXML.outputfile";
  
      /**
       * For the list of zip files given on the command line, create component XML descriptor files
       * for the mary component installer.
       * <br/>
       * The zip file names are expected to have the following structure:
       * <code>mary-</code>(component name)<code>-</code>(version number)<code>.zip</zip>
       * <br/>
       * If the component name is a locale, a language component xml is created; otherwise, 
       * a voice component xml is created.
       * <br/>
       * The program will look in the following folders for existing xml:
       * <ul>
       * <li>if a folder is passed as the system property <code>mary.componentXML.folder</code>, that folder and no other folder;</li>
       * <li>otherwise:</li>
       * <ul>
       *     <li>the folders in which the zip files are located;</li>
       *     <li>the current folder;</li>
       *     <li>the folders <code>download/</code> and <code>installed/</code> below the current folder;</li>
       * </ul>    
       * </ul>
       * If existing xml files contain a component with the same name, any information that can not be automatically computed
       * (such as description, voice gender, synthesis technology etc.) will be copied from that component.
       * <br/>
       * The resulting files will by default be written into individual xml files located in the
       * same folder as the respective zip file, and named
       * <code>mary-</code>(component name)<code>-</code>(version number)<code>-component.xml</code>.
       * Alternatively, if the system property <code>mary.componentXML.outputfile</code> is set, 
       * this is used as the filename of a single XML file combining the component names.
       *
       * @param args zip files for which component xml is to be generated
       */
   /*   public static void main(String[] args) throws Exception {
          // Write some documentation if appropriate:
          if (System.getProperty(PROPERTY_XML_OUTPUTFILE) == null) {
              System.out.println("You can indicate a single output file for the generated XML with -D"+PROPERTY_XML_OUTPUTFILE+"=(filename)");
              System.out.println();
          }
          if (System.getProperty(PROPERTY_XML_FOLDER) == null) {
              System.out.println("You can indicate a folder containing existing component XML files with -D"+PROPERTY_XML_FOLDER+"=(foldername)");
              System.out.println();
          }
          
          // Where to write output
          boolean writeIndividualXML = true;
          File outputFile = null;
          Document allXML = null;
          String outputFilename = System.getProperty(PROPERTY_XML_OUTPUTFILE);
          if (outputFilename != null) {
              outputFile = new File(outputFilename);
              writeIndividualXML = false;
              
          }
          // Where to look for known records:
          Set<File> xmlFolders = new HashSet<File>();
          boolean haveCustomXMLFolder = false;
          String customXMLFolder = System.getProperty(PROPERTY_XML_FOLDER);
          if (customXMLFolder != null) {
              haveCustomXMLFolder = true;
              File custom = new File(customXMLFolder);
              if (!custom.isDirectory()) {
                  throw new FileNotFoundException("Custom XML folder '"+customXMLFolder+"' was specified in system properties but does not exist!");
              }
              xmlFolders.add(custom);
          } else {
              xmlFolders.add(new File("."));
              File downloadFolder = new File("./download");
              if (downloadFolder.isDirectory()) {
                  xmlFolders.add(downloadFolder);
              }
              File installedFolder = new File("./installed");
              if (installedFolder.isDirectory()) {
                  xmlFolders.add(installedFolder);
              }
          }
          // Jobs
          List<File> zips = new ArrayList<File>(args.length);
          for (String a : args) {
              File f = new File(a);
              if (!f.canRead()) {
                  throw new FileNotFoundException("Cannot read file: "+a);
              }
              if (!f.getName().startsWith("mary-") || !f.getName().endsWith(".zip")) {
                  throw new IllegalArgumentException("File '"+f.getName()+" doesn't follow convention 'mary-(name)-(version).zip'");
              }
              zips.add(f);
              if (!haveCustomXMLFolder) {
                  xmlFolders.add(f.getAbsoluteFile().getParentFile());
              }
          }
          // Read known records
          Map<String, ComponentDescription> knownComponents = new TreeMap<String, ComponentDescription>();
          for (File folder : xmlFolders) {
              File[] xmlFiles = folder.listFiles(new FilenameFilter() {
                  @Override
  				public boolean accept(File dir, String name) {
                      return name.endsWith(".xml");
                  }
              });
              for (File xmlFile : xmlFiles) {
                  try {
                      InstallFileParser ifp = new InstallFileParser(xmlFile.toURI().toURL());
                      for (ComponentDescription cd : ifp.getLanguageDescriptions()) {
                          knownComponents.put(cd.getName(), cd);
                      }
                      for (ComponentDescription cd : ifp.getVoiceDescriptions()) {
                          knownComponents.put(cd.getName(), cd);
                      }
                  } catch (Exception e) {
                      
                      System.err.println("Cannot load existing xml file "+xmlFile.getAbsolutePath()+" -- ignoring.");
                      e.printStackTrace();
                      
                  }
              }
          }
          System.out.print("Loaded known component descriptions: ");
          for (String componentName : knownComponents.keySet()) {
              System.out.print(componentName+"("+knownComponents.get(componentName).getVersion()+") ");
          }
          System.out.println();
          System.out.println();
  
          // Now go through the zip files and try to create suitable component descriptions
          Set<ComponentDescription> newDescriptions = new TreeSet<ComponentDescription>();
          Set<Locale> existingLocales = new HashSet<Locale>(Arrays.asList(Locale.getAvailableLocales()));
          existingLocales.add(new Locale("te")); // Telugu
          for (File zip : zips) {
              String name;
              String version;
              // Filename convention: mary-(name)-(version).zip
              String filename = zip.getName();
              assert filename.startsWith("mary-");
              int nameStart = "mary-".length();
              int versionEnd = filename.length() - ".zip".length();
              int lastDash = filename.lastIndexOf('-', versionEnd);
              if (lastDash != -1) { // have a dash, normal
                  name = filename.substring(nameStart, lastDash);
                  version = filename.substring(lastDash+1, versionEnd);
              } else { // no dash, treat as version "unknown"
                  name = filename.substring(nameStart, versionEnd);
                  version = "unknown";
              }
              Locale l = MaryUtils.string2locale(name); // this will work even if it's nonsense
              boolean isLanguageComponent = existingLocales.contains(l);
              boolean haveKnownComponent = knownComponents.containsKey(name);
              System.out.println((isLanguageComponent ? "Language" : "Voice") + " component "+name+", version "+version
                      + (haveKnownComponent ? " (have component description for version "+knownComponents.get(name).getVersion()+")" : ""));
              // Create a component description that describes this zip file as appropriately as possible
              ComponentDescription cd;
              if (isLanguageComponent) {
                  cd = new LanguageComponentDescription(name, version, filename);
                  cd.setLocale(MaryUtils.string2locale(name));
              } else {
                  VoiceComponentDescription vcd = new VoiceComponentDescription(name, version, filename);
                  if (haveKnownComponent) {
                      VoiceComponentDescription old = (VoiceComponentDescription) knownComponents.get(name);
                      vcd.setGender(old.getGender());
                      vcd.setType(old.getType());
                      vcd.setDependsLanguage(old.getDependsLanguage());
                      vcd.setDependsVersion(old.getDependsVersion());
                      vcd.setLocale(old.getLocale());
                  } else {
                      vcd.setGender("unknown");
                      vcd.setType("unknown");
                      vcd.setDependsLanguage("unknown");
                      vcd.setDependsVersion(version);
                      vcd.setLocale(new Locale("unknown"));
                  }
                  cd = vcd;
              }
              // Hard facts:
              cd.setPackageSize((int)zip.length());
              cd.setPackageMD5Sum(MD5.asHex(MD5.getHash(zip)));
              // Further description elements:
              if (haveKnownComponent) {
                  ComponentDescription old = knownComponents.get(name);
                  cd.setDescription(old.getDescription());
                  cd.setLicenseURL(old.getLicenseURL());
                  for (URL loc : old.getLocations()) {
                      cd.addLocation(loc);
                  }
              } else { // need to guess
                  cd.setDescription(" ");
                  if (isLanguageComponent) { // assume LGPL
                      cd.setLicenseURL(new URL("http://www.gnu.org/licenses/lgpl-3.0-standalone.html"));
                  } else { // voice, assume by-nd
                      cd.setLicenseURL(new URL("http://mary.dfki.de/download/by-nd-3.0.html"));
                  }
                  cd.addLocation(new URL("http://mary.dfki.de/download/"+version+"/"+filename));
              }
              // Now get the XML description to the right place:
              Document oneXML = cd.createComponentXML(); 
              if (writeIndividualXML) {
                  File oneXMLFile = new File(zip.getParentFile(), "mary-"+name+"-"+version+"-component.xml");
                  DomUtils.document2File(oneXML, oneXMLFile);
                  System.out.println("Wrote "+oneXMLFile.getPath());
              } else { // combine them all into allXML, then write at the end
                  if (allXML == null) {
                      allXML = oneXML;
                  } else {
                      Node compDesc = oneXML.getDocumentElement().getElementsByTagName(cd.getComponentTypeString()).item(0);
                      allXML.getDocumentElement().appendChild(allXML.adoptNode(compDesc));
                  }
              }
          }
          if (!writeIndividualXML && allXML != null) {
              DomUtils.document2File(allXML, outputFile);
              System.out.println("Wrote "+outputFile.getPath());
          }
      }*/
  
  }
  