/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.vinci.transport;

import java.io.UTFDataFormatException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.vinci.transport.util.Base64Converter;
import org.apache.vinci.transport.util.Base64FormatException;
import org.apache.vinci.transport.util.UTFConverter;

/**
 * Class encapsulating leaf data from a Frame. Internally, leaf data is always represented as UTF-8.
 * Most people will never have to use this class directly unless implementing specialized Frame
 * document types.
 * 
 * While FrameLeaf is effectively an immutable class, any descendents that implement setAttributes
 * of the base class FrameComponent are not likely to be immutable.
 */

public class FrameLeaf extends FrameComponent {
  /**
   * If you call toString() on a FrameLeaf which contains binary data, you get this string as the
   * result.
   */
  static public final String NOT_UTF8_ERROR = "*** ERROR: Data not utf8 ***";

  private final byte[] data;

  /**
   * Create a frameleaf from existing UTF-8 (or true binary) data.
   * 
   * WARNING: Does not copy the array. Caller is responsible for ensuring the provided byte array
   * cannot be modified by external code.
   * 
   * @pre mydata != null
   * @param mydata -
   * @param encode -
   */
  public FrameLeaf(byte[] mydata, boolean encode) {
    if (encode) {
      this.data = Base64Converter.convertBinaryToBase64(mydata);
    } else {
      // data must be valid UTF-8 unless using binary transport hack.
      this.data = mydata;
    }
  }

  /**
   * @pre mydata != null
   * @param mydata -
   */
  public FrameLeaf(String mydata) {
    this.data = UTFConverter.convertStringToUTF(mydata);
  }

  /**
   * This method does NOT support null values in the array.
   * 
   * @pre mystring != null
   * @pre { for (int i = 0; i &lt; mystring.length; i++) $assert(mystring[i] != null, "array elements
   *      are non-null"); }
   * @param mystring -
   */
  public FrameLeaf(String[] mystring) {
    String separator = "#";
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < mystring.length; i++) {
      if (mystring[i].indexOf(separator) != -1) {
        separator += String.valueOf((int) (Math.random() * 10));
        i--;
      }
    }
    if (separator.length() > 1) {
      separator += "#";
      buf.append(separator);
    }
    for (int i = 0; i < mystring.length; i++) {
      if (i != 0) {
        buf.append(separator);
      }
      buf.append(mystring[i]);
    }
    this.data = UTFConverter.convertStringToUTF(buf.toString());
  }

  public FrameLeaf(float myfloat_) {
    this(Float.toString(myfloat_));
  }

  /**
   * @pre myfloat != null
   * @param myfloat -
   */
  public FrameLeaf(float[] myfloat) {
    StringBuffer add_me = new StringBuffer();
    for (int i = 0; i < myfloat.length; i++) {
      add_me.append(Float.toString(myfloat[i]));
      if (i != myfloat.length - 1) {
        add_me.append(' ');
      }
    }
    this.data = UTFConverter.convertStringToUTF(add_me.toString());
  }

  public FrameLeaf(double myfloat) {
    this(Double.toString(myfloat));
  }

  /**
   * @pre mydouble != null
   * @param mydouble -
   */
  public FrameLeaf(double[] mydouble) {
    StringBuffer add_me = new StringBuffer();
    for (int i = 0; i < mydouble.length; i++) {
      /** @pre mydouble[i] != null */
      add_me.append(Double.toString(mydouble[i]));
      if (i != mydouble.length - 1) {
        add_me.append(' ');
      }
    }
    this.data = UTFConverter.convertStringToUTF(add_me.toString());
  }

  public FrameLeaf(int myint_) {
    this(Integer.toString(myint_));
  }

  /**
   * @pre myint != null
   * @param myint -
   */
  public FrameLeaf(int[] myint) {
    StringBuffer add_me = new StringBuffer();
    for (int i = 0; i < myint.length; i++) {
      /** @pre myint[i] != null */
      add_me.append(Integer.toString(myint[i]));
      if (i != myint.length - 1) {
        add_me.append(' ');
      }
    }
    this.data = UTFConverter.convertStringToUTF(add_me.toString());
  }

  public FrameLeaf(long myint) {
    this(Long.toString(myint));
  }

  /**
   * @pre mylong != null
   * @param mylong -
   */
  public FrameLeaf(long[] mylong) {
    StringBuffer add_me = new StringBuffer();
    for (int i = 0; i < mylong.length; i++) {
      /** @pre mylong[i] != null */
      add_me.append(Long.toString(mylong[i]));
      if (i != mylong.length - 1) {
        add_me.append(' ');
      }
    }
    this.data = UTFConverter.convertStringToUTF(add_me.toString());
  }

  public FrameLeaf(boolean bool) {
    this(bool ? TransportConstants.TRUE_VALUE : TransportConstants.FALSE_VALUE);
  }

  public String toString() {
    try {
      return UTFConverter.convertUTFToString(data);
    } catch (UTFDataFormatException e) {
      // E-frame data should ALWAYS be valid UTF
      // ^^ Except due to hack methods for transporting pure binary without B64 overhead
      return NOT_UTF8_ERROR;
    }
  }

  public String[] toStringArray() {
    String work = toString();
    if (work.indexOf('#') == -1) {
      if (work.length() > 0) {
        String[] return_me = new String[1];
        return_me[0] = work;
        return return_me;
      } else {
        return new String[0];
      }
    } else if (work.charAt(0) != '#') {
      // This would be so much easier with JDK1.4 split()
      int size = 0;
      for (int i = 0; i < work.length(); i++) {
        if (work.charAt(i) == '#') {
          size++;
        }
      }
      size++;
      String[] return_me = new String[size];
      int begin = 0;
      int end = 0;
      for (int i = 0; i < size - 1; i++) {
        end = work.indexOf('#', begin + 1);
        return_me[i] = work.substring(begin, end);
        begin = end + 1;
      }
      return_me[size - 1] = work.substring(begin);
      return return_me;
    } else {
      // This would be so much easier with JDK1.4 split()
      int end = work.indexOf('#', 1);
      if (end == -1) {
        throw new LeafCastException("Not a string array: " + toString());
      }
      String separator = work.substring(0, end + 1);
      int begin = end + 1;
      List strings = new ArrayList();
      while ((end = work.indexOf(separator, begin)) != -1) {
        strings.add(work.substring(begin, end));
        begin = end + separator.length();
      }
      strings.add(work.substring(begin));
      String[] return_me = new String[strings.size()];
      for (int i = 0; i < return_me.length; i++) {
        return_me[i] = strings.get(i).toString();
      }
      return return_me;
    }
  }

  /**
   * Get the raw (usually UTF-8) frame data.
   * @return -
   */
  public byte[] getData() {
    return data;
  }

  /**
   * Converts the B64 encoded data to binary and returns it.
   * 
   * @exception LeafCastException
   *              if the data was not base64 encoded.
   * @return -
   */
  public byte[] toBytes() {
    try {
      return Base64Converter.convertBase64ToBinary(data);
    } catch (Base64FormatException e) {
      throw new LeafCastException("Not base64: " + e.getMessage());
    }
  }

  /**
   * Converts the UTF-8 data to a Java long type.
   * 
   * @exception LeafCastException
   *              if the data could not be converted to long.
   * @return -
   */
  public long toLong() {
    try {
      return UTFConverter.convertUTFToLong(data);
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Not an integer: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java array of longs.
   * 
   * @exception LeafCastException
   *              if the data could not be convered to a long array.
   * @return -
   */
  public long[] toLongArray() {
    try {
      String array_string = UTFConverter.convertUTFToString(data);
      StringTokenizer tokenizer = new StringTokenizer(array_string);
      List tokens = new ArrayList();
      while (tokenizer.hasMoreTokens()) {
        tokens.add(tokenizer.nextToken());
      }
      long[] return_me = new long[tokens.size()];
      for (int i = 0; i < tokens.size(); i++) {
        return_me[i] = Long.parseLong((String) (tokens.get(i)));
      }
      return return_me;
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Array contains non-long: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java int type.
   * 
   * @exception LeafCastException
   *              if the data could not be converted to int.
   * @return -
   */
  public int toInt() {
    try {
      return UTFConverter.convertUTFToInt(data);
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Not an integer: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java array of ints.
   * 
   * @exception LeafCastException
   *              if the data could not be convered to an int array.
   * @return -
   */
  public int[] toIntArray() {
    try {
      String array_string = UTFConverter.convertUTFToString(data);
      StringTokenizer tokenizer = new StringTokenizer(array_string);
      List tokens = new ArrayList();
      while (tokenizer.hasMoreTokens()) {
        tokens.add(tokenizer.nextToken());
      }
      int[] return_me = new int[tokens.size()];
      for (int i = 0; i < tokens.size(); i++) {
        return_me[i] = Integer.parseInt((String) (tokens.get(i)));
      }
      return return_me;
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Array contains non-integer: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java float type.
   * 
   * @exception LeafCastException
   *              if the data could not be converted to float.
   * @return -
   */
  public float toFloat() {
    try {
      return UTFConverter.convertUTFToFloat(data);
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Not a float: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java array of float.
   * 
   * @exception LeafCastException
   *              if the data could not be convered to a float array.
   * @return -
   */
  public float[] toFloatArray() {
    try {
      String array_string = UTFConverter.convertUTFToString(data);
      StringTokenizer tokenizer = new StringTokenizer(array_string);
      List tokens = new ArrayList();
      while (tokenizer.hasMoreTokens()) {
        tokens.add(tokenizer.nextToken());
      }
      float[] return_me = new float[tokens.size()];
      for (int i = 0; i < tokens.size(); i++) {
        return_me[i] = Float.parseFloat((String) (tokens.get(i)));
      }
      return return_me;
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Array contains non-float: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java double type.
   * 
   * @exception LeafCastException
   *              if the data could not be converted to double.
   * @return -
   */
  public double toDouble() {
    try {
      return UTFConverter.convertUTFToDouble(data);
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Not a double: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java array of double.
   * 
   * @exception LeafCastException
   *              if the data could not be convered to a double array.
   * @return -
   */
  public double[] toDoubleArray() {
    try {
      String array_string = UTFConverter.convertUTFToString(data);
      StringTokenizer tokenizer = new StringTokenizer(array_string);
      List tokens = new ArrayList();
      while (tokenizer.hasMoreTokens()) {
        tokens.add(tokenizer.nextToken());
      }
      double[] return_me = new double[tokens.size()];
      for (int i = 0; i < tokens.size(); i++) {
        return_me[i] = Double.parseDouble((String) (tokens.get(i)));
      }
      return return_me;
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    } catch (NumberFormatException e) {
      throw new LeafCastException("Array contains non-double: " + toString());
    }
  }

  /**
   * Converts the UTF-8 data to a Java boolean.
   * 
   * @exception LeafCastException
   *              if the underlying data was not utf-8 (which in general should not happen).
   * @return -
   */
  public boolean toBoolean() {
    try {
      return UTFConverter.convertUTFToBool(data);
    } catch (UTFDataFormatException e) {
      throw new LeafCastException(NOT_UTF8_ERROR);
    }
  }

}
