package org.timepedia.chronoscope.utils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;

import org.timepedia.chronoscope.client.ChronoscopeComponentFactory;
import org.timepedia.chronoscope.client.Dataset;
import org.timepedia.chronoscope.client.Datasets;
import org.timepedia.chronoscope.client.data.json.JsonArray;
import org.timepedia.chronoscope.client.data.json.JsonArrayNumber;
import org.timepedia.chronoscope.client.data.json.JsonArrayString;
import org.timepedia.chronoscope.client.data.json.JsonDataset;
import org.timepedia.chronoscope.client.io.DatasetReader;
import org.timepedia.chronoscope.client.util.DateFormatter;
import org.timepedia.chronoscope.client.util.date.DateFormatterFactory;

import com.google.gwt.i18n.client.TimeZone;

/**
 * Utility class to pre-mip a json data string.
 * 
 * @author manolo carrasco moñino
 */
public class JsonMipper {
  
  public static class GwtJsonArrayNumber implements JsonArrayNumber {
    private JSONArray jsa;
    
    public GwtJsonArrayNumber (JSONArray jsa) {
      this.jsa = jsa;
    }
    
    public double get(int i) {
      return jsa.getDouble(i);
    }

    public int length() {
      return jsa.size();
    }
  }
  
  public static class GwtJsonArrays implements JsonArray<JsonArrayNumber> {
    private JSONArray jsa;
    
    public GwtJsonArrays (JSONArray jsa){
      this.jsa = jsa;
    }

    public JsonArrayNumber get(int i) {
      return new GwtJsonArrayNumber(jsa.getJSONArray(i));
    }

    public int length() {
      return jsa.size();
    }
  };
  
  public static class GwtJsonArrayString implements JsonArrayString {
    private JSONArray jsa;
    
    public GwtJsonArrayString (JSONArray jsa){
      this.jsa = jsa;
    }
    
    public String get(int i) {
      return jsa.getString(i);
    } 

    public int length() {
      return jsa.size();
    }
  }  
  
  public static class GwtJsonDataset implements JsonDataset {
    private JSONObject jso;

    public GwtJsonDataset(JSONObject jso) {
      this.jso = jso;
    }

    public String getAxisId() {
      return jso.getString("axis");
    }

    public String getDateTimeFormat() {
      return jso.has("dtformat") ? jso.getString("dtformat") : null;
    }

    public JsonArrayNumber getDomain() {
      return new GwtJsonArrayNumber(jso.getJSONArray("domain"));
    }

    public double getDomainScale() {
      return jso.has("domainscale") ? jso.getDouble("domainscale") : 1;
    }

    public JsonArrayString getDomainString() {
      return new GwtJsonArrayString(jso.getJSONArray("domain"));
    }

    public String getId() {
      return jso.has("id") ? jso.getString("id") : null;
    }

    public String getLabel() {
      return jso.has("label") ? jso.getString("label") : null;
    }

    public JsonArray<JsonArrayNumber> getMultiDomain() {
      return new GwtJsonArrays(jso.getJSONArray("domain"));   
    }

    public JsonArray<JsonArrayNumber> getMultiRange() {
      return new GwtJsonArrays(jso.getJSONArray("range"));   
    }

    public String getPartitionStrategy() {
      return jso.has("partitionStrategy") ? jso.getString("partitionStrategy") : "binary";
    }

    public String getPreferredRenderer() {
      return jso.has("preferredRenderer") ? jso.getString("preferredRenderer") : "line";
    }

    public JsonArrayNumber getRange() {
      return new GwtJsonArrayNumber(jso.getJSONArray("range"));
    }

    public double getRangeBottom() {
      return jso.has("rangeBotton") ? jso.getDouble("rangeBotton") : Double.NaN;
    }

    public double getRangeTop() {
      return jso.has("rangeTop") ? jso.getDouble("rangeTop") : Double.NaN;
    }

    public JsonArray<JsonArrayNumber> getTupleRange() {
      return jso.has("tupleRange") ? new GwtJsonArrays(jso.getJSONArray("tupleRange")) : null;   
    }

    public boolean hasRangeInformation() {
      return jso.has("rangeTop") ? jso.getBoolean("rangeTop") : false;
    }

    public boolean isMipped() {
      return jso.has("mipped") ? jso.getBoolean("mipped") : false;
    }
    
  }
  
  public static class JDKDateFormatter implements DateFormatter {

    private SimpleDateFormat fmt;

    public JDKDateFormatter(String format) {
        fmt = new SimpleDateFormat(format);
    }

    public String format(double timestamp) {
      return fmt.format(new Date((long) timestamp));
    }

    public String format(double timestamp, TimeZone timezone) {
        return fmt.format(new Date((long) timestamp));
    }

    public double parse(String date) {
        try {
            return fmt.parse(date).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
            return 0;
        }
    }
  }
  
  public static class JDKDateFormatterFactory extends DateFormatterFactory {
    public DateFormatter getDateFormatter(String format) {
      return new JDKDateFormatter(format);
    }
  }

  
  private static ChronoscopeComponentFactory componentFactory = new ChronoscopeComponentFactory();
  
  
  private static DatasetReader datasetReader = new DatasetReader(componentFactory);

  static {
    DateFormatterFactory.setDateFormatterFactory(new JDKDateFormatterFactory());
  }
  
  private static String readFileAsString(String file)
  throws java.io.IOException{
      StringBuffer fileData = new StringBuffer();
      BufferedReader reader = new BufferedReader(new FileReader(file));
      char[] buf = new char[4096];
      int read;
      while((read = reader.read(buf)) != -1){
          fileData.append(buf, 0, read);
      }
      reader.close();
      return fileData.toString().trim();
  }
  
  public static void main(String...args) throws Exception {
    JsonMipper mipper = new JsonMipper(); 
    for (String s: args) {
      System.out.println(mipper.mipJsonFile(s));
    }
  }
  
  public String mipJsonFile(String filename) throws IOException {
    return mipJsonString(readFileAsString(filename));
  }
  
  public String mipJsonString(String jsonTxt) {
    boolean multiple = jsonTxt.startsWith("[");
    String varName = null;
    if (jsonTxt.matches("(?s)^\\s*([\\w]+)\\s*=\\s*.*")) {
      varName = jsonTxt.replaceFirst("(?s)^\\s*([\\w]+)\\s*=\\s*.*", "$1");
    }
    if (varName != null) {
      jsonTxt = jsonTxt.replaceFirst("(?s)\\s*([\\w]+)\\s*=\\s*(.*?)\\s*\\;?\\s*$", "$2");
    }
    
    if (jsonTxt.startsWith("{")) {
      jsonTxt = "{datasets: [" + jsonTxt + "]}";
    } else if (jsonTxt.startsWith("[")) {
      jsonTxt = "{datasets: " + jsonTxt + "}";
    }
    
    JSONObject json = (JSONObject) JSONSerializer.toJSON(jsonTxt); 
    JSONArray  sets = json.getJSONArray("datasets");
    
    Datasets dsets = new Datasets();
    for (int i=0; i < sets.size(); i++) {
      JSONObject set = sets.getJSONObject(i);
      GwtJsonDataset s = new GwtJsonDataset(set);
      Dataset d = datasetReader.createDatasetFromJson(s);
      dsets.add(d);
    }
    
    String mippedJson;
    if (multiple) {
      mippedJson = dsets.toJson();
    } else {
      mippedJson = dsets.get(0).toJson();
    }
    
    if (varName != null) {
      mippedJson = varName + " = " + mippedJson + ";";
    }
    
    return mippedJson;
  }
  
}

@@ -1061,9 +1061,9 @@
 o mo
-%C3%B1
+n
 ino%0A

remove non ascii character