# -------------------------------------------------------------------
# ORTHOGRAPHIC
# Your personal aerial satellite. Always on. At any altitude.*
# Developed by MarStrMind
# License: Open Software License 3.0
# Up to date version always on marstr.online
# -------------------------------------------------------------------
# xp_scenery.py
# This class builds an elevation mesh from provided DEM data, and
# generates all required files that are needed to provide a usable
# scenery package for X-Plane.
# -------------------------------------------------------------------

import os
import math
import urllib.request
from defines import *
from log import *

class mstr_xp_scenery:
    # Set required variables
    def __init__(self, lat, lng, mlat, mlng, vstep, latlngfld):
        mstr_msg("xp_scenery", "[X-Plane] Scenery generator instantiated")
        self._lat = lat
        self._lng = lng
        self._mlat = mlat
        self._mlng = mlng
        self._vstep = vstep
        self._latlngfld = latlngfld
        self._demfn = self.build_dem_filename()


    # Build the correct file name for the elevation model
    def build_dem_filename(self, xes=False):
        fn = ""
        if self._lat > 0:
            fn = fn + "N"
        else:
            fn = fn + "S"

        if abs(self._lat) < 10: fn = fn + "0" + str(self._lat)
        if abs(self._lat) >= 10 and abs(self._lat) <= 90: fn = fn + str(self._lat)

        if self._lng > 0:
            fn = fn + "E"
        else:
            fn = fn + "W"

        if abs(self._lng) < 10: fn = fn + "00" + str(self._lng)
        if abs(self._lng) >= 10 and abs(self._lng) <= 99: fn = fn + "0" + str(self._lng)
        if abs(self._lng) >= 100 : fn = fn + str(self._lng)

        if xes == False:
            fn = fn + ".hgt"
        if xes == True:
            fn = fn + ".xes"

        mstr_msg("xp_scenery", "[X-Plane] DEM file name constructed: " + fn)

        return fn

    # Generate the mesh script for the ortho photos
    def build_mesh_script(self):
        scr = mstr_datafolder + "z_orthographic/data/meshscript.txt"
        # Before we blast all these lines into the file, we need to make sure they do not exist already
        write_lines = True

        if os.path.isfile(scr) == True:
            fnlines = []
            with open(scr) as textfile:
                fnlines = textfile.readlines()

            for line in fnlines:
                l = line.split(" ")
                if l[2] == str(self._lng) and l[3] == str(self._lat):
                    write_lines = False
                    break
        else:
            open(scr, 'a').close()
        
        # If we did not find the initial corner coordinate in the script, we can go ahead
        if write_lines == True:
            mstr_msg("xp_scenery", "[X-Plane] Writing mesh script file")
            # We basically run through all tiles and note down the position of the orthos
            # as needed by X-Plane. 
            cur_lat = self._lat
            cur_lng = self._lng
            for lat in range(1, self._mlat+1):
                for lng in range(1, self._mlng+1):
                    # Write the line only if an ortho exists of course.
                    if os.path.isfile(mstr_datafolder + "z_orthographic/" + self._latlngfld + "/orthos/" + str(lat) + "_" + str(lng) + ".dds" ) == True:
                        # The '1' after 'ORTHOPHOTO' defines we want water underneath transparent parts of the DDS texture/ortho.
                        # This ensures that even if the mesh does not include information for there being a water body,
                        # we will get 100% correct representation of the water bodies.
                        scrtxt = "ORTHOPHOTO 1 " + str(cur_lng) + " " + str(cur_lat) + " " + str(round(cur_lng+mstr_zl_18, 6)) + " " + str(cur_lat) + " " + str(round(cur_lng+mstr_zl_18, 6)) + " " + str(round(cur_lat+self._vstep, 6)) + " " + str(cur_lng) + " " + str(round(cur_lat+self._vstep, 6)) + " terrain/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".ter\n"

                        with open(scr, 'a') as textfile:
                            textfile.write(scrtxt)

                    cur_lng = round(cur_lng + mstr_zl_18, 6)

                cur_lng = self._lng
                cur_lat = round(cur_lat + self._vstep, 6)
            mstr_msg("xp_scenery", "[X-Plane] Mesh script completed")


    # Find the next "by-ten" numbers for the current latitude and longitude
    def find_earthnavdata_number(self):
        earthnavdata = []
        lat = abs(int(self._lat / 10) * 10)
        lng = abs(int(self._lng / 10) * 10)
        earthnavdata.append(lat)
        earthnavdata.append(lng)
        return earthnavdata


    # Construct an X-Plane compatible folder name for latitude and longitude
    def xplane_latlng_folder(self, numbers):
        fstr = ""
        if numbers[0] >= 0: fstr = "+"
        if numbers[0] <  0: fstr = "-"
        if abs(numbers[0]) < 10: fstr = fstr + "0" + str(numbers[0])
        if abs(numbers[0]) >= 10 and numbers[0] <= 90: fstr = fstr + str(numbers[0])

        if numbers[1] >= 0: fstr = fstr + "+"
        if numbers[1] <  0: fstr = fstr + "-"
        if abs(numbers[1]) < 10: fstr = fstr + "00" + str(numbers[1])
        if abs(numbers[1]) >= 10 and numbers[0] <= 99: fstr = fstr + "0" + str(numbers[1])
        if abs(numbers[1]) >= 100 : fstr = fstr + str(numbers[1])

        return fstr


    # Acquires the elevation data as needed -
    # you can either acquire the older STRM set with lower resolution,
    # or a modern LIDAR scan with higher resolution. However, the
    # LIDAR files are much larger and generates a more taxing mesh.
    # If you are testing, acquire the low resolution file.
    # Both versions are coming from my repository at marstr.online .
    def acquire_elevation_data(self):
        mstr_msg("xp_scenery", "[X-Plane] Acquiring DEM model data")
        url = "https://marstr.online/dem/"

        url = url + self._demfn

        urllib.request.urlretrieve(url, mstr_datafolder + "_cache/" + self._demfn)
        mstr_msg("xp_scenery", "[X-Plane] DEM data acquired")


    # Download the X-Plane definition file from my server
    def acquire_xes_data(self):
        mstr_msg("xp_scenery", "[X-Plane] Acquiring XES file")
        url = "https://marstr.online/xes/"
        xesfn = self.build_dem_filename(True)

        xp_folder = self.xplane_latlng_folder([self._lat, self._lng])
        url = url + xp_folder + ".xes"

        urllib.request.urlretrieve(url, mstr_datafolder + "_cache/" + xesfn)
        mstr_msg("xp_scenery", "[X-Plane] XES data acquired")


    # This builds the entire mesh in one go
    def build_mesh(self):
        mstr_msg("xp_scenery", "[X-Plane] Building DSF mesh")
        end_bt = self.find_earthnavdata_number()
        btlfn = str(self.xplane_latlng_folder(end_bt))
        xp_folder = self.xplane_latlng_folder([self._lat, self._lng])
        scr = mstr_datafolder + "z_orthographic/data/meshscript.txt"
        wd = mstr_datafolder + "z_orthographic/data"
        dsf = mstr_datafolder + "z_orthographic/Earth nav data/" + btlfn + "/" + xp_folder
        xesfn = self.build_dem_filename(True)

        # The main command to build the mesh
        cmd = mstr_xp_meshtool + " \"" + scr + "\" \"" + mstr_datafolder + "_cache/" + xesfn + "\"" + " \"" + mstr_datafolder + "_cache/" + self._demfn + "\" \"" + wd + "\" \"" + dsf + ".dsf\""

        os.system(cmd)

        mstr_msg("xp_scenery", "[X-Plane] Mesh construction complete")


    # This generates all .ter files
    def build_ter_files(self):
        mstr_msg("xp_scenery", "[X-Plane] Generating and writing terrain (.ter) files")
        cur_lat = self._lat
        cur_lng = self._lng
        xp_folder = self.xplane_latlng_folder([self._lat, self._lng])
        for lat in range(1, self._mlat+1):
            for lng in range(1, self._mlng+1):
                terstr = ""
                terstr = terstr + "A\n"
                terstr = terstr + "800\n"
                terstr = terstr + "TERRAIN\n"
                terstr = terstr + "\n"
                terstr = terstr + "BASE_TEX_NOWRAP ../orthos/"+xp_folder+"/"+str(lat)+"_"+str(lng)+".dds\n"
                if mstr_xp_scn_normalmaps == True:
                    terstr = terstr + "TEXTURE_NORMAL ../normals/"+xp_folder+"/"+str(lat)+"_"+str(lng)+".dds\n"

                terfln = mstr_datafolder + "z_orthographic/terrain/"+xp_folder+"/"+str(lat)+"_"+str(lng)+".ter"

                with open(terfln, 'w') as textfile:
                    textfile.write(terstr)

        mstr_msg("xp_scenery", "[X-Plane] Terrain files written")