package yi.util.io.output;

import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import yi.util.config.*;

public abstract class DOU implements DataOutputUnit {

  public String FILE_POSTFIX = "";

  /**
   * Which format to use for output
   */
  public final static int OUTPUT_NONE = 0;
  public final static int OUTPUT_SER  = 1;
  public final static int OUTPUT_XML  = 2;
  public final static int OUTPUT_CSV  = 4;
  public final static int OUTPUT_ALL  = 0xFF;

  /**
   * Name connection character
   */
  public final static char CONNECT_CHAR = '.';
  public final static String DEFAULT_SOURCE_NAME = "default";

  private static DOU m_singleton = null;

  /**
   * It is used to remember whether how many times a output name is used.  When
   * a file name is used to output the first time, a index number "1" is appended
   * to the filename; the second time, "2" is appended...
   */
  private HashMap m_outputInstances = new HashMap();

  public static String DOU_TYPE = "yi.util.io.output.DOU_Xml";

  protected DOU() {
  }

  /**
   * Use Configuration parameter to generate the default data output unit
   * instance.
   * @return
   */
  public static DOU getSingleton() {
    if (m_singleton != null) return m_singleton;

    // get the data output unit type from Configuration
    DOU_TYPE = Configuration.getStringParameter(
        "DOU_TYPE", DOU_TYPE);
    try {
      Class c = Class.forName(DOU_TYPE);
      m_singleton = (DOU)c.newInstance();
    }
    catch (ClassNotFoundException e) {
      System.err.println("Can't find the data output unit specified");
      e.printStackTrace();
      m_singleton = DOU_Xml.getSingleton();
    }
    catch (Exception e) {
      System.err.println("Not a valid class for data output unit");
      e.printStackTrace();
      m_singleton = DOU_Xml.getSingleton();
    }
    return m_singleton;
  }

  /**
   * Use default data output unit instance to output
   * @param sourceName
   * @param producerName
   * @param dataName
   * @param obj
   */
  public void output(String sourceName, String producerName, String dataName, Object obj)
  throws DataOutputException {
    getSingleton().output(sourceName, producerName, dataName, obj);
  }

  /**
   * Output the object to user-specified destination (in "where")
   * @param where combination of OUTPUT_SER and OUTPUT_XML. OUTPUT_ALL and
   *              OUTPUT_NONE are also available
   * @param sourceName
   * @param producerName
   * @param dataName
   * @param obj
   */
  public void output(int where,
    String sourceName, String producerName, String dataName, Object obj)
  throws DataOutputException{
    if ((where & OUTPUT_SER) > 0) {
      DOU_Ser.getSingleton().output(sourceName, producerName, dataName, obj);
    }
    if ((where & OUTPUT_XML) > 0) {
      DOU_Xml.getSingleton().output(sourceName, producerName, dataName, obj);
    }
    if ((where & OUTPUT_CSV) > 0) {
      DOU_Csv.getSingleton().output(sourceName, producerName, dataName, obj);
    }

  }

  public static void out(int where, String producerName, String dataName, Object obj)
  throws DataOutputException{
      String sourceName = Configuration.getStringParameter("SOURCE_NAME", DEFAULT_SOURCE_NAME);
      String destPath = Configuration.getStringParameter("DEST_PATH", "");
      String output_name = destPath + sourceName;
      yi.util.io.File.makeDirectory(output_name, true);
      getSingleton().output(where, output_name, producerName, dataName, obj);
  }

  public static void out(int where, String sourceName,
    String producerName, String dataName, Object obj)
  throws DataOutputException{
      getSingleton().output(where, sourceName, producerName, dataName, obj);
  }

  /**
   * When a DOU want to output to a file, it will first see how many time this
   * name is used.  It then append that name with a index number.  The name is
   * 1 based. (the first time, return index 1)
   * @param instanceName
   * @return
   */
  protected String getInstanceName(String instanceName) {
    return getInstanceName(instanceName, true);
  }

  /**
   * When a DOU want to output to a file, it will first see how many time this
   * name is used.  It then append that name with a index number.  The name is
   * 1 based. (the first time, return index 1).
   * @param instanceName
   * @param increaseCounter whether the counter will be increased
   * @return
   */
  protected String getInstanceName(String instanceName, boolean increaseCounter) {
    if (!m_outputInstances.containsKey(instanceName)) {
      m_outputInstances.put(instanceName, new Integer(0));
    }
    Integer index = (Integer)m_outputInstances.get(instanceName);
    index = new Integer(index.intValue() + 1);
    if (increaseCounter) m_outputInstances.put(instanceName, index);
    return instanceName + index;
  }

  /**
   * This is a utility function helps convert a full class name to short name
   * (eg, yi.iu.processor.color.DPU_DominantColor -> DPU_DominantColor)
   * @param className
   */
  public static String shortName(String className) {
    int index = className.lastIndexOf('.');
    return className.substring(index + 1);
  }

  /**
   * Return the output file name
   * @param sourceName
   * @param producerName
   * @param dataName
   * @return
   */
  public String getOutputFileName(String sourceName, String producerName, String dataName) {
    return getInstanceName(sourceName + CONNECT_CHAR + producerName +
      CONNECT_CHAR + dataName, false) + FILE_POSTFIX;
  }

  public static String getOutputFileName(int where, String sourceName, String producerName, String dataName) {
    if ((where & OUTPUT_SER) > 0) {
      return DOU_Ser.getSingleton().getOutputFileName(sourceName, producerName, dataName);
    }
    if ((where & OUTPUT_XML) > 0) {
      return DOU_Xml.getSingleton().getOutputFileName(sourceName, producerName, dataName);
    }
    if ((where & OUTPUT_CSV) > 0) {
      return DOU_Csv.getSingleton().getOutputFileName(sourceName, producerName, dataName);
    }
    return null;
  }
}