/*
 *************************************************************************************
 * Copyright (C) 2009-2010, Google Inc., International Business Machines Corporation,*
 * and others. All Rights Reserved.                                                  *
 *************************************************************************************
 */

package org.unicode.cldr.icu;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

import org.unicode.cldr.icu.ICUResourceWriter.Resource;
import org.unicode.cldr.icu.ICUResourceWriter.ResourceTable;
import org.unicode.cldr.util.LDMLUtilities;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

public abstract class SimpleLDMLConverter {
  protected final ICULog log;
  protected final String fileName;
  protected final String supplementalDir;
  protected final String tableName;

  public SimpleLDMLConverter(ICULog log, String fileName, String supplementalDir,
      String tableName) {
    this.log = log;
    this.fileName = fileName;
    this.supplementalDir = supplementalDir;
    this.tableName = tableName;
  }

  public void convert(ICUWriter writer) {
    Document document = createDocument();

    log.log("Processing " + fileName);
    Resource res = parseDocument(document, fileName);
  
    if (res != null && ((ResourceTable)res).first != null) {
      writer.writeResource(res, fileName);
    }
  }

  public Document createDocument() {
    FilenameFilter filter = createDocumentFilter();
  
    File myDir = new File(supplementalDir);
    String[] files = myDir.list(filter);
    if (files == null) {
      String canonicalPath;
      try {
        canonicalPath = myDir.getCanonicalPath();
      } catch (IOException e) {
        canonicalPath = e.getMessage();
      }
      log.error("Supplemental files are missing " + canonicalPath);
      System.exit(-1);
    }

    String dirPath = myDir.getAbsolutePath();
    Document doc = null;
    for (String fileName : files) {
      try {
        log.info("Parsing document " + fileName);
        String filePath = dirPath + File.separator + fileName;
        Document child = LDMLUtilities.parse(filePath, false);
        if (doc == null) {
          doc = child;
          continue;
        }
        StringBuilder xpath = new StringBuilder();
        LDMLUtilities.mergeLDMLDocuments(doc, child, xpath, fileName, dirPath, true, false);
      } catch (Throwable se) {
        log.error("Parsing: " + fileName + " " + se.toString(), se);
        System.exit(1);
      }
    }
  
    return doc;
  }

  protected FilenameFilter createDocumentFilter() {
    FilenameFilter filter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        if (name.matches(fileName)) {
          return true;
        }
        return false;
      }
    };
    return filter;
  }
  
  protected Resource parseDocument(Node root, String sourceInfo) {
    log.setStatus(sourceInfo);
    ResourceTable table = new ResourceTable();
    Resource current = null;
    StringBuilder xpath = new StringBuilder();
    xpath.append("//");
    xpath.append(LDMLConstants.SUPPLEMENTAL_DATA);
    table.name = tableName;
    table.annotation = ResourceTable.NO_FALLBACK;
    int savedLength = xpath.length();
    for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
      if (node.getNodeType() != Node.ELEMENT_NODE) {
        continue;
      }

      if (node.getNodeName().equals(LDMLConstants.SUPPLEMENTAL_DATA)) {
        // Stop iterating over top-level elements, restart iterating over elements
        // under supplementalData.
        node = node.getFirstChild();
        continue;
      }
      
      Resource res = parseElement(node, xpath);
  
      if (res != null) {
        if (current == null) {
          table.first = res;
          current = res.end();
        } else {
          current.next = res;
          current = res.end();
        }
        res = null;
      }
      xpath.delete(savedLength, xpath.length());
    }
  
    return table;
  }
  
  protected Resource parseElement(Node node, StringBuilder xpath) {
    String name = node.getNodeName();
    Resource res = null;

    if (name.equals(tableName)) {
      res = parseInfo(node, xpath);
    } else if (name.equals(LDMLConstants.VERSION) || name.equals(LDMLConstants.GENERATION) || name.equals(LDMLConstants.CLDR_VERSION)) {
      // ignore
    } else {
      log.error("Unknown element " + LDML2ICUConverter.getXPath(node, xpath).toString());
      System.exit(-1);
    }
    return res;
  }

  protected abstract Resource parseInfo(Node root, StringBuilder xpath);
}
