package edu.utah.cs.trajectory

import java.io.{BufferedWriter, File, FileWriter}

import com.vividsolutions.jts.geom.{GeometryCollection, GeometryFactory}
import edu.utah.cs.partitioner.STRSegPartition
import edu.utah.cs.spatial.{LineSegment, MBR, Point, Polygon}
import edu.utah.cs.util.{BloomFilter, BloomFilterMeta}
import org.apache.spark.{SparkConf, SparkContext}
import org.geotools.geojson.geom.GeometryJSON

/**
  * Created by dongx on 10/24/16.
  */
object LineSegmentClustering {
  final val max_entries_per_node = 25
  final val k = 10
  final val N = 34085

  def main(args: Array[String]): Unit = {
    val sc = new SparkContext(new SparkConf().setAppName("LineSegmentClustering"))

    if (args.length < 2) {
      println("usage: SpatialSpanClustering <input_file_path> <output_file_path>")
      System.exit(1)
    }

    val input_file_path = args(0)
    val output_file_path = args(1)

    val dataRDD = sc.textFile(input_file_path)
      .map(x => x.split('\t'))
      .map(x => (LineSegment(Point(Array(x(2).toDouble, x(1).toDouble)),
        Point(Array(x(4).toDouble, x(3).toDouble))),
        TrajMeta(x(0).toInt, x(5).toInt)))

    val bf_meta = BloomFilterMeta(N, 1)
    val bc_bf_meta = sc.broadcast(bf_meta)
    BloomFilter.meta = bf_meta

    val num_partitions = dataRDD.getNumPartitions
    val (partitioned_rdd, part_mbrs) = STRSegPartition(dataRDD, num_partitions, 0.01, max_entries_per_node)

    val part_bounds = partitioned_rdd.mapPartitions(iter => {
      if (iter.nonEmpty) {
        var maxx = Double.MinValue
        var maxy = Double.MinValue
        var minx = Double.MaxValue
        var miny = Double.MaxValue
        iter.map(_._1).foreach(x => {
          maxx = Math.max(Math.max(x.start.coord(0), x.end.coord(0)), maxx)
          maxy = Math.max(Math.max(x.start.coord(1), x.end.coord(1)), maxy)
          minx = Math.min(Math.min(x.start.coord(0), x.end.coord(0)), minx)
          miny = Math.min(Math.min(x.start.coord(1), x.end.coord(1)), miny)
        })
        Array(MBR(Point(Array(minx, miny)), Point(Array(maxx, maxy)))).iterator
      } else Array().iterator
    }).collect()

    val file = new File(output_file_path)
    val bw = new BufferedWriter(new FileWriter(file))

    val collection = new GeometryCollection(part_bounds.map(x =>
      Polygon(Array(x.low, Point(Array(x.low.coord(0), x.high.coord(1))),
        x.high, Point(Array(x.high.coord(0), x.low.coord(1))), x.low)).content), new GeometryFactory)

    new GeometryJSON().writeGeometryCollection(collection, bw)

    bw.close()

    sc.stop()
  }
}