from qgis.PyQt.QtCore import (
  QT_TRANSLATE_NOOP, QVariant
  )
from qgis.core import (
  QgsProcessing,
  QgsProcessingParameterFeatureSource,
  QgsProcessingParameterFeatureSink,
  QgsProcessingParameterBoolean,
  QgsFeatureRequest,
  QgsProcessingParameterCrs,
  QgsVectorLayer
  )

from .initabstract import initabstract

from qgis import processing
import sys

class initroad(initabstract):
  PARAMETERS = {                  
    "INPUT": {
      "ui_func": QgsProcessingParameterFeatureSource,
      "ui_args":{
        "description": QT_TRANSLATE_NOOP("initroad","Line layer"),
        "types": [QgsProcessing.TypeVectorLine],
        "optional": True
      }
    },
    "USE_ZVALUE": {
      "ui_func": QgsProcessingParameterBoolean,
      "ui_args":{
        "description" : QT_TRANSLATE_NOOP("initroad","Use z values of the geometry?"),
        "defaultValue": False
      }
    },
    "TARGET_CRS": {
      "ui_func": QgsProcessingParameterCrs,
      "ui_args": {
        "description": QT_TRANSLATE_NOOP("fetchroadja","Target CRS (Cartesian coordinates)")
      }
    },
    "OVERWRITE": {
      "ui_func": QgsProcessingParameterBoolean,
      "ui_args":{
        "description" : QT_TRANSLATE_NOOP("initroad","Overwrite existing fields?"),
        "defaultValue": True
      }
    },
    "OUTPUT": {
      "ui_func": QgsProcessingParameterFeatureSink,
      "ui_args": {
        "description": QT_TRANSLATE_NOOP("initroad","Road" )
      }
    }
  }
  
  def __init__(self):
    super().__init__()
    self.FIELDS_REQUIRED.update(
      {    
        "LV_d":       {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average light vehicle count (6-18h)
        "LV_e":       {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average light vehicle count (18-22h)
        "LV_n":       {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average light vehicle count (22-6h)
        "MV_d":       {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average medium heavy vehicle count (6-18h)
        "MV_e":       {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average medium heavy vehicle count (18-22h)
        "MV_n":       {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average medium heavy vehicle count (22-6h)
        "HGV_d":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average heavy duty vehicles count (6-18h)
        "HGV_e":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average heavy duty vehicles count (18-22h)
        "HGV_n":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average heavy duty vehicles count (22-6h)
        "WAV_d":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average mopeds < 50cc count (6-18h)
        "WAV_e":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average mopeds < 50cc count (18-22h)
        "WAV_n":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average mopeds < 50cc count (22-6h)
        "WBV_d":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average motorcycle > 50cc count (6-18h)
        "WBV_e":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average motorcycle > 50cc count (18-22h)
        "WBV_n":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Hourly average motorcycle > 50cc count (22-6h)
        "LV_spd_d":   {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average light vehicle speed (6-18h)
        "LV_spd_e":   {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average light vehicle speed (18-22h)
        "LV_spd_n":   {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average light vehicle speed (22-6h)
        "MV_spd_d":   {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average medium heavy vehicle speed (6-18h)
        "MV_spd_e":   {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average medium heavy vehicle speed (18-22h)
        "MV_spd_n":   {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average medium heavy vehicle speed (22-6h)
        "HGV_spd_d":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average heavy duty vehicles speed (6-18h)
        "HGV_spd_e":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average heavy duty vehicles speed (18-22h)
        "HGV_spd_n":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average heavy duty vehicles speed (22-6h)
        "WAV_spd_d":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average mopeds < 50cc speed (6-18h)
        "WAV_spd_e":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average mopeds < 50cc speed (18-22h)
        "WAV_spd_n":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average mopeds < 50cc speed (22-6h)
        "WBV_spd_d":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average motorcycle > 50cc speed (6-18h)
        "WBV_spd_e":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average motorcycle > 50cc speed (18-22h)
        "WBV_spd_n":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 60.0}, # Hourly average motorcycle > 50cc speed (22-6h)
        "LWd63":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 63 Hz (dB) (6-18h)
        "LWd125":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 125 Hz (dB) (6-18h)
        "LWd250":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 250 Hz (dB) (6-18h)
        "LWd500":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 500 Hz (dB) (6-18h)
        "LWd1000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 1000 Hz (dB) (6-18h)
        "LWd2000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 2000 Hz (dB) (6-18h)
        "LWd4000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 4000 Hz (dB) (6-18h)
        "LWd8000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 8000 Hz (dB) (6-18h)
        "LWe63":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 63 Hz (dB) (18-22h)
        "LWe125":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 125 Hz (dB) (18-22h)
        "LWe250":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 250 Hz (dB) (18-22h)
        "LWe500":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 500 Hz (dB) (18-22h)
        "LWe1000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 1000 Hz (dB) (18-22h)
        "LWe2000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 2000 Hz (dB) (18-22h)
        "LWe4000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 4000 Hz (dB) (18-22h)
        "LWe8000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 8000 Hz (dB) (18-22h)
        "LWn63":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 63 Hz (dB) (22-6h)
        "LWn125":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 125 Hz (dB) (22-6h)
        "LWn250":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 250 Hz (dB) (22-6h)
        "LWn500":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 500 Hz (dB) (22-6h)
        "LWn1000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 1000 Hz (dB) (22-6h)
        "LWn2000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 2000 Hz (dB) (22-6h)
        "LWn4000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 4000 Hz (dB) (22-6h)
        "LWn8000":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Octave-band sound power level at 8000 Hz (dB) (22-6h)
        "pvmt":       {"TYPE": QVariant.String, "DEFAULT_VALUE": "DEF"}, # CNOSSOS road pavement identifier
        "temp_d":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": 20.0}, # Average temperature (6-18h)
        "temp_e":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": 20.0}, # Average temperature (18-22h)
        "temp_n":     {"TYPE": QVariant.Double, "DEFAULT_VALUE": 20.0}, # Average temperature (22-6h)
        "ts_stud":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # A limited period Ts (in months) over the year where a average proportion pm_stud of light vehicles are equipped with studded tyres (6-18h)
        "pm_stud":    {"TYPE": QVariant.Double, "DEFAULT_VALUE": None}, # Average proportion of vehicles equipped with studded tyres during ts_stud period
        "junc_dist":  {"TYPE": QVariant.Double, "DEFAULT_VALUE": 999.0}, # Distance to junction in meters
        "junc_type":  {"TYPE": QVariant.Int,    "DEFAULT_VALUE": 0}, # Type of junction (k=0 none, k = 1 for a crossing with traffic lights ; k = 2 for a roundabout)
        "slope":      {"TYPE": QVariant.Double, "DEFAULT_VALUE": 0}, # Slope (in %) of the road section. If the field is not filled in, the LINESTRING z-values will be used
        "way":        {"TYPE": QVariant.Int   , "DEFAULT_VALUE": 3} # the way of the road section. 1 = one way road section and the traffic goes in the same way that the slope definition you have used, 2 = one way road section and the traffic goes in the inverse way that the slope definition you have used, 3 = bi-directional traffic flow, the flow is split into two components and correct half for uphill and half for downhill
      }
    )
  # LD: light vehicle
  # MD: medium heavy vehicle, delivery vans > 3.5 tons,  buses, touring cars, etc. with two axles and twin tyre mounting on rear axle
  # HGV: heavy duty vehicles, touring cars, buses, with three or more axles
  # WAV: mopeds, tricycles or quads < 50 cc
  # WBV: motorcycles, tricycles or quads > 50 cc
  
  def initAlgorithm(self, config):
    (rect, target_crs) = self.getExtentAndCrsUsingCanvas()
    self.PARAMETERS["TARGET_CRS"]["ui_args"]["defaultValue"] = target_crs.authid()

    self.initParameters()
    
  def processAlgorithm(self, parameters, context, feedback):
    target_crs = self.parameterAsCrs(parameters, "TARGET_CRS", context)
    # check whether the target CRS is x-y coordinates
    if target_crs.isGeographic() or target_crs.authid() == "EPSG:3857":
      sys.exit(self.tr("The Target CRS is NOT a Cartesian Coordinate System"))

    try:
      self.INPUT_LAYER = processing.run(
        "native:reprojectlayer", 
        {
          "INPUT": self.parameterAsSource(parameters, "INPUT", context).materialize(QgsFeatureRequest(), feedback),
          "TARGET_CRS": target_crs,
          "OUTPUT": "TEMPORARY_OUTPUT"
        }
      )["OUTPUT"]      
            
    except:
      self.INPUT_LAYER = QgsVectorLayer(f"LineString?crs={target_crs.authid()}", "temp", "memory")
    
    if self.parameterAsBoolean(parameters, "USE_ZVALUE", context):
      test_geom = self.INPUT_LAYER.getFeatures().__next__().geometry()
      if test_geom.get().nCoordinates() != 3:
        sys.exit(self.tr("The input layer has no Z values!"))
    else:
      self.INPUT_LAYER = processing.run(
        "native:setzvalue",
        {
          "INPUT": self.INPUT_LAYER,
          "Z_VALUE": 0.05,
          "OUTPUT": "TEMPORARY_OUTPUT"
        }
      )["OUTPUT"]
      
    self.setFieldsDict(
      parameters, context, feedback, 
      self.INPUT_LAYER.fields(), 
      self.parameterAsBoolean(parameters, "OVERWRITE", context)
    )
    
    # define the feature sink
    (sink, dest_id) = self.parameterAsSink(
      parameters, "OUTPUT", context, 
      self.FIELDS_INIT, 
      self.INPUT_LAYER.wkbType(), 
      self.INPUT_LAYER.sourceCrs()
    )
    
    self.resetPk()    
    self.addFeaturesToSink(sink, dest_id, self.INPUT_LAYER)
              
    return {"OUTPUT": dest_id}
  
  def createInstance(self):
    return initroad()


  def displayName(self):
    return self.tr("Road with acoustic information")

  def group(self):
    return self.tr("Initialize features")

  def groupId(self):
    return "initfeature"

  def createInstance(self):
    return initroad()
