import javax.imageio.ImageIO

import java.awt.Point
import java.awt.Rectangle
import java.awt.image.BufferedImage
import java.awt.image.AffineTransformOp
import java.awt.geom.Point2D
import java.awt.geom.Rectangle2D

import java.awt.geom.AffineTransform

import javax.media.jai.JAI

import java.awt.image.ColorModel
import java.awt.image.DataBuffer
import java.awt.image.DataBufferByte
import java.awt.image.WritableRaster

import joms.oms.WmsMap

import joms.oms.DataInfo

import org.ossim.oms.image.omsImageSource

import org.grails.plugins.springsecurity.service.AuthenticateService

class OgcController
{
  def webMappingService
  def dataInfo = new DataInfo()
  //def parser = new OmsInfoParser()
  def grailsApplication
  AuthenticateService authenticateService

  def wms = {

    def tempMap = [:]

    // Convert param names to lower case
    params.each { tempMap.put(it.key.toLowerCase(), it.value)}

    // Populate WMSCapabilities Request object
    def wmsRequest = new WMSRequest()


    bindData(wmsRequest, tempMap)

    //println wmsRequest


    try
    {
      switch ( wmsRequest?.request?.toLowerCase() )
      {
        case "getmap":

          switch ( wmsRequest?.format?.toLowerCase() )
          {
            case "jpeg":
            case "jpg":
            case "image/jpeg":
            case "image/jpg":
              if ( wmsRequest?.transparent?.equalsIgnoreCase("true") )
              {
                wmsRequest.format = "image/png"
                response.contentType = "image/png"
              }
              else
              {
                response.contentType = "image/jpeg"
              }
              break
            case "png":
            case "image/png":
              response.contentType = "image/png"
              break
            case "gif":
            case "image/gif":
              response.contentType = "image/gif"
              break
          }

          def starttime = System.currentTimeMillis()
          def image = webMappingService.getMap(wmsRequest)

          ImageIO.write(image, response.contentType?.split("/")[-1], response.outputStream)

          def endtime = System.currentTimeMillis()
          def principal = authenticateService.principal()

          //if ( principal != "anonymousUser" )
          //{
            //def user = principal.username

            def logData = [
              TYPE: "wms_getmap",
              START: new Date(starttime),
              END: new Date(endtime),
              ELAPSE_TIME_MILLIS: endtime - starttime,
              //USER: user,
              PARAMS: wmsRequest,
              MODE: webMappingService.mode
            ]
            log.info(logData)
          //}
          break
        case "getcapabilities":
          def serviceAddress = createLink(controller: "ogc", action: "wms", absolute: true)
          def capabilities = webMappingService?.getCapabilities(wmsRequest, serviceAddress)

          render(contentType: "text/xml", text: capabilities)
          break
        case "getkml":
          def serviceAddress = createLink(controller: "ogc", action: "wms", absolute: true)
          def kml = webMappingService.getKML(wmsRequest, serviceAddress)

          response.setHeader("Content-disposition", "attachment; filename=foo.kml")
          render(contentType: "application/vnd.google-earth.kml+xml", text: kml, encoding: "UTF-8")
          break
        default:
          println "ERROR: Unknown action: ${wmsRequest?.request}"
      }
    }
    catch (java.lang.Exception e)
    {
      println "OGC::WMS Error: ${e.message}"
    }

    return null
  }

  def getTile = {


    def image = null
    def tileWidth = params.tileWidth?.toInteger()
    def tileHeight = params.tileHeight?.toInteger()
    def offsetX = Math.round( params.x?.toDouble() * tileWidth ) as Integer;
    def offsetY = Math.round( params.y?.toDouble() * tileHeight ) as Integer;


    try
    {
      //println "params: $params"

      def mode = "OSSIM"
      def rect = new Rectangle(offsetX, offsetY, tileWidth, tileHeight)
      def width
      def height

      switch ( mode )
      {
        case "JAI":
          image = JAI.create("imageread", inputFile)

          def raster = image.getData(rect).createTranslatedChild(0, 0)

          image = new BufferedImage(image.colorModel, raster, false, null)
          width = image.width
          height = image.height
          break

        case "OSSIM":
          def rasterEntry = RasterEntry.get(params.id)
          def inputFile = rasterEntry.mainFile.name

          width = rasterEntry?.width
          height = rasterEntry?.height

          def numRLevels = 1
          def tileSize = 256
          def targetFullRect = (2**params.z?.toInteger())*tileSize;

//          while ( width > tileSize )
//          {
//            width /= 2
//            height /= 2
//            numRLevels++
//          }
          def maxDimension =width;
          if(maxDimension < height)
          {
            maxDimension = height;
          }
          def scale = (double)targetFullRect/(double)maxDimension;
          def outputType = "jpeg"
          def resLevel = numRLevels - params.z?.toInteger() - 1
          def startSample = rect.x
          def endSample = rect.x + rect.width - 1
          def startLine = rect.y
          def endLine = rect.y + rect.height - 1
          def outputFile = File.createTempFile("ogcoms", ".jpg")
          def entry = rasterEntry.entryId?.toInteger()

          def mode2 = "LIBCALL"
          def stretchMode = params?.stretch_mode ?: "linear_auto_min_max";
          def stretchModeRegion =   params?.stretch_mode_region ?: "global"
          def viewportStretchMode = ""

          if(stretchModeRegion.equals("viewport"))
          {
            viewportStretchMode = stretchMode;
            stretchMode = "";
          }
        else
          {
            viewportStretchMode = "";
          }
          switch ( mode2 )
          {
            case "SYSCALL":
              def cmd = "icp --res-level ${resLevel} --start-sample ${startSample} --end-sample ${endSample} --start-line ${startLine} --end-line ${endLine}  --use-scalar-remapper --entry ${entry} --writer-prop 'create_external_geometry=false' ${outputType} ${inputFile}  ${outputFile}"

              //println "$cmd"

              def process = cmd.execute()

              process.consumeProcessOutput()
              process.waitFor();
              image = ImageIO.read(outputFile)
              outputFile.delete()
              // delete the geom file
              new File(outputFile.absolutePath - "jpg" + "geom").delete()
              break
            case "LIBCALL":
              byte[] data = new byte[rect.width * rect.height * 3]

              WmsMap.getUnprojectedMap(
                  inputFile, entry,
                  "",
                  stretchMode,
                  viewportStretchMode,
                  scale, 
                  startSample, endSample, startLine, endLine,
                  data
              )
              DataBuffer dataBuffer = new DataBufferByte(data, data.size())
              int pixelStride = 3
              int lineStride = 3 * rect.width
              int[] bandOffsets = [0, 1, 2] as int[]
              Point location = null
              WritableRaster raster = WritableRaster.createInterleavedRaster(
                  dataBuffer,
                  rect.width as Integer,
                  rect.height as Integer,
                  lineStride,
                  pixelStride,
                  bandOffsets,
                  location)

              ColorModel colorModel = omsImageSource.createColorModel(raster.sampleModel)

              boolean isRasterPremultiplied = true
              Hashtable<?, ?> properties = null

              image = new BufferedImage(
                  colorModel,
                  raster,
                  isRasterPremultiplied,
                  properties
              )

              break
          }
          break
      }
      response.contentType = "image/jpeg"
      ImageIO.write(image, "jpeg", response.outputStream)
    }
    catch (Exception e)
    {
      println "OGC::GetTile Error: ${e.message}"
      image = new BufferedImage(tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB)

      response.contentType = "image/jpeg"
      ImageIO.write(image, "jpeg", response.outputStream)

    }
  }
}