/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package foam.core;

import foam.dao.pg.IndexedPreparedStatement;
import foam.nanos.logger.Logger;
import java.lang.UnsupportedOperationException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public abstract class AbstractArrayPropertyInfo
  extends AbstractPropertyInfo
{
  @Override
  public void setFromString(Object obj, String value) {
    if ( value == null ) {
      this.set(obj, null);
      return;
    }
    java.util.List<String> list = new java.util.LinkedList<String>();
    StringBuilder sb = new StringBuilder(); 
    char prev = '$';
    int length = value.length();
    char[] cs = value.toCharArray();
    for ( int i = 0 ; i < cs.length ; i++ ) {
      if ( cs[i] == '\\' ) {
        if ( prev == '\\' ) {
          sb.append("\\");
          prev = '$';
        } else {
          prev = '\\';
        }
      } else if ( cs[i] == ',' ) {
        if ( prev == '\\' ) {
          sb.append(',');
        } else {
          list.add(sb.toString());
          sb.setLength(0);
        }
        prev = '$';
      } else {
        sb.append(cs[i]);
        prev = cs[i];
      }
    }
    list.add(sb.toString());
    int resultSize = list.size();
    System.out.println("list size: " + list.size());
    String[] result = new String[resultSize];
    //add support for other array types
    this.set(obj, list.subList(0, resultSize).toArray(result));
  }

  public abstract String of();

  // NESTED ARRAY
  @Override
  public Object fromXML(X x, XMLStreamReader reader) {
    List objList = new ArrayList();
    String startTag = reader.getLocalName();
    try {
      int eventType;
      while ( reader.hasNext() ) {
        eventType = reader.next();
        switch ( eventType ) {
          case XMLStreamConstants.START_ELEMENT:
            if ( reader.getLocalName().equals("value") ) {
              // TODO: TYPE CASTING FOR PROPER CONVERSION. NEED FURTHER SUPPORT FOR PRIMITIVE TYPES
              throw new UnsupportedOperationException("Primitive typed array XML reading is not supported yet");
            }
            break;
          case XMLStreamConstants.END_ELEMENT:
            if ( reader.getLocalName() == startTag ) { return objList.toArray(); }
        }
      }
    } catch (XMLStreamException ex) {
      Logger logger = (Logger) x.get("logger");
      logger.error("Premature end of XML file");
    }
    return objList.toArray();
  }

  @Override
  public void toXML (FObject obj, Document doc, Element objElement) {
    if ( this.f(obj) == null ) return;

    Element prop = doc.createElement(this.getName());
    objElement.appendChild(prop);

    Object[] nestObj = (Object[]) this.f(obj);
    for ( int k = 0; k < nestObj.length; k++ ) {
      Element nestedProp = doc.createElement("value");
      nestedProp.appendChild(doc.createTextNode(nestObj[k].toString()));
      prop.appendChild(nestedProp);
    }
  }

  @Override
  public void setStatementValue(IndexedPreparedStatement stmt, FObject o) throws java.sql.SQLException {
    Object obj = this.get(o);
    if ( obj == null ) {
      stmt.setObject(null);
      return;
    }
    Object[] os = (Object[]) obj;
    java.lang.StringBuilder sb = new java.lang.StringBuilder();
    int length = os.length;
    if ( length == 0 ) {
      stmt.setObject(null);
      return;
    }
    for ( int i = 0 ; i < length ; i++ ) {
      if ( os[i] == null )
        sb.append("");
      else {
        sb.append(os[i].toString().replace("\\","\\\\").replace(",","\\,"));
      }
      if ( i < length - 1 ) {
        sb.append(",");
      }
    }
    stmt.setObject(sb.toString());
  }

  @Override
  public void setFromResultSet(java.sql.ResultSet resultSet, int index, FObject o) throws java.sql.SQLException{
    String value = (String) resultSet.getObject(index);
    setFromString(o, value);
  }
}

@@ -287,24 +287,53 @@
 .ArrayList;%0A
+import java.util.LinkedList;%0A
 import java.
@@ -757,26 +757,90 @@
   %7D%0A    
-java.util.
+// TODO: TO REUSE THIS LIST WITH A THREADLOCAL FOR BETTER PERFORMANCE%0A    
 List%3CStr
@@ -855,26 +855,16 @@
 t = new 
-java.util.
 LinkedLi
@@ -1561,61 +1561,8 @@
 ();%0A
-    System.out.println(%22list size: %22 + list.size());%0A
     
@@ -1670,31 +1670,8 @@
 ist.
-subList(0, resultSize).
 toAr
@@ -3437,26 +3437,16 @@
 bj;%0A    
-java.lang.
 StringBu
@@ -3460,26 +3460,16 @@
 b = new 
-java.lang.
 StringBu
@@ -3696,74 +3696,39 @@
     
-sb.a
+escapeCommasAndA
 ppend(
+sb, 
 os%5Bi%5D
-.toString().replace(%22%5C%5C%22,%22%5C%5C%5C%5C%22).replace(%22,%22,%22%5C%5C,%22)
 );%0A 
@@ -3965,16 +3965,17 @@
 xception
+ 
 %7B%0A    St
@@ -4056,11 +4056,287 @@
 ue);%0A  %7D
+%0A%0A  private void escapeCommasAndAppend(StringBuilder builder, Object o) %7B%0A    String s = o.toString();%0A    //replace backslash to double backslash%0A    s = s.replace(%22%5C%5C%22, %22%5C%5C%5C%5C%22);%0A    //replace comma to backslash+comma%0A    s = s.replace(%22,%22, %22%5C%5C,%22);%0A    builder.append(s);%0A  %7D
 %0A%7D%0A

add helper function to regex; import java.util.LinkedList; fix setFromString()