/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

import ilog.views.maps.IlvAttributeInfoProperty;
import ilog.views.maps.IlvCoordinate;
import ilog.views.maps.IlvFeatureAttributeProperty;
import ilog.views.maps.IlvFeatureRenderer;
import ilog.views.maps.IlvMapFeature;
import ilog.views.maps.IlvMapFeatureIterator;
import ilog.views.maps.attribute.IlvStringAttribute;
import ilog.views.maps.format.IlvMapFormatException;
import ilog.views.maps.geometry.IlvMapLineString;
import ilog.views.maps.projection.IlvProjection;
import ilog.views.maps.rendering.IlvDefaultCurveRenderer;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.StringTokenizer;

/**
 * Read polylines from simple text files.
 * File format is one point per line, in the order longitude then
 * latitude in decimal degrees. A third field can contain a comment to be
 * attached to polyline as a string attribute. Each field is separated by
 * spaces.
 * A file can contain multiple polylines : each polyline is separated from
 * another by a blank line.
 */
class SimplePolylineReader
  implements IlvMapFeatureIterator
{
  /**
   * The attribute info for attributes
   */
  private IlvAttributeInfoProperty attributeInfo;

  /**
   * A decimal parser to parse decimal numbers
   */
  private DecimalFormat decimalParser;

  /**
   * The input stream from which file are read
   */
  private BufferedReader file;

  /**
   * Constructs a new PolylineReader to read from file which name is
   * specified.
   * @param fileName the name of file to read
   */
  public SimplePolylineReader(String fileName) 
    throws IOException, IlvMapFormatException
  {
    file = new BufferedReader(new FileReader(fileName));
    // check file format
    String line = file.readLine();
    if ((line == null) ||
        (!line.trim().equals("# ascii polylines"))) {
      file.close();
      throw new IlvMapFormatException("Wrong format");
    }

    // to parse coordinates
    decimalParser = new DecimalFormat();

    // Build attribute info
    String attributeNames[] = { "Comment" };
    Class  attributeClasses[] = { IlvStringAttribute.class };
    boolean attributeNullable[] = { true };

    attributeInfo = new IlvAttributeInfoProperty(attributeNames,
                                                 attributeClasses,
                                                 attributeNullable);
  }
  /**
   * Release the resources allocated by the feature iterator
   */
  public void dispose ()
  {
    if (file != null) {
      try {
        file.close();
      } catch (IOException exception) {
        /* DO NOTHING */
      }
    }
  }
  /**
   * Returns next feature from collection, or null if no more
   * feature is available.
   */
  public IlvMapFeature getNextFeature()
    throws IOException
  {
    return readPolyline();
  }

  /**
   * Returns true if the reader can provide the source projection
   * of its map features.
   */
  public boolean isGeoreferenced()
  {
    return true;
  }

  /**
   * Returns the projection of the features
   */
  public IlvProjection getProjection()
  {
    return null; // DEPRECATED
  }

  /**
   * Returns the coordinate system of the features
   */
  public IlvCoordinateSystem getCoordinateSystem()
  {
    return IlvGeographicCoordinateSystem.WGS84;
  }

  /**
   * Returns the upper left corner of the feature list.
   */
  public IlvCoordinate getUpperLeftCorner()
  {
    return null;
  }
  
  /**
   * Returns the lower right corner of the feature list.
   */
  public IlvCoordinate getLowerRightCorner()
  {
    return null;
  }  
  
  /**
   * Returns the default renderer for the map features.
   */
  public IlvFeatureRenderer getDefaultFeatureRenderer()
  {
    return new IlvDefaultCurveRenderer();
  }

  /**
   * Reads the polyline from file
   */
  private IlvMapFeature readPolyline() 
    throws IOException
  {   
    // a buffer to concatenate all comments for a polyline
    StringBuffer buffer = new StringBuffer();
    // the current read feature
    IlvMapFeature feature = new IlvMapFeature();
    // the current read line string geometry
    IlvMapLineString geometry = new IlvMapLineString();
   
    // to store the line of text that is read
    String line;
    
    // read a line
    while ((line = file.readLine()) != null) {
      line = line.trim();
      if (line.length() == 0) {
        break;
      }
      
      // for analyse of the line
      StringTokenizer tokenizer = new StringTokenizer(line," \t");
      String currentToken;

      // process longitude
      IlvCoordinate c = new IlvCoordinate();

      if (tokenizer.hasMoreElements() == false)
        throw new IlvMapFormatException("Longitude coordinate expected");
      try {
        currentToken = (String)tokenizer.nextElement();
        c.x = decimalParser.parse(currentToken).doubleValue();
      } catch (ParseException e) {
        throw new IlvMapFormatException("Error while parsing longitude");
      }

      // process latitude
     if (tokenizer.hasMoreElements() == false)
        throw new IlvMapFormatException("Latitude coordinate expected");
      try {
        currentToken = (String)tokenizer.nextElement();
        c.y = decimalParser.parse(currentToken).doubleValue();
      } catch (ParseException e) {
        throw new IlvMapFormatException("Error while parsing latitude");
      }

      // process comment
      while (tokenizer.hasMoreElements()) {
        buffer.append((String)tokenizer.nextElement());
        buffer.append(" ");
      }

      // add this point to geometry
      geometry.addPoint(c);
    } 

    // Case of end of file
    if ((line == null) && (geometry.getPointCount() == 0))
      return null;

    // Initialize feature
    feature.setGeometry(geometry);
 
    // Set attribute
    IlvStringAttribute[] attribute = new IlvStringAttribute[1];
    if (buffer.length() > 0) {
      attribute[0] = new IlvStringAttribute();
      attribute[0].setString(buffer.toString());
    } else {
      attribute[0] = null;
    }
    feature.setAttributeInfo(attributeInfo);
    feature.setAttributes(new IlvFeatureAttributeProperty(attributeInfo,
                                                          attribute));

    // return the read feature
    return feature;
  }
}