# -*- coding: utf-8 -*-
# Copyright (C) 2017-2021 Davide Gessa
# Copyright (C) 2021 Enrico Ferreguti
# Copyright (C) 2012 Riccardo Apolloni
'''
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

For detail about GNU see <http://www.gnu.org/licenses/>.
'''
from typing import Tuple 
from io import FileIO
import math

class Polar:
    def __init__ (self, polarPath: str, f: FileIO = None):
        """
        Parameters
        ----------
        polarPath : string
            Path of the polar file
        f : File
            File object for passing an opened file
        """

        self.tws = []
        self.twa = []
        self.vmgdict = {}
        self.speedTable = []
        
        if f == None:
            f = open (polarPath, "r")
        
        tws = f.readline ().split ()
        for i in range (1,len(tws)):
            self.tws.append (float (tws[i].replace ('\x02', '')))

        line = f.readline ()
        while line != "":
            data = line.split ()
            twa = float (data[0])
            self.twa.append (math.radians (twa))
            speedline = []
            for i in range (1,len (data)):
                speed = float (data[i])
                speedline.append (speed)
            self.speedTable.append (speedline)
            line = f.readline ()
        f.close ()


    def toString(self) -> str:
        s = 'TWA\\TWS'
        for x in self.tws:
            s += '\t%d' % x
        s += '\n'

        l = 0
        for y in self.twa:
            s += '%d' % round(math.degrees(y))
            sl = self.speedTable[l]

            for x in sl:
                s += '\t{:.1f}'.format(x)
            s += '\n'

            l += 1

        return s
        
    def getSpeed (self, tws: float, twa: float) -> float:
        """ Returns the speed (in knots) given tws (in knots) and twa (in radians) """
        
        tws1 = 0
        tws2 = 0
        for k in range(0, len(self.tws)):
            if tws >= self.tws[k]:
               tws1 = k
        for k in range(len(self.tws) - 1, 0, -1):
            if tws <= self.tws[k]:
                tws2 = k
        if tws1 > tws2: # TWS over table limits
            tws2 = len(self.tws) - 1
        twa1 = 0
        twa2 = 0
        for k in range(0, len(self.twa)):
            if twa >= self.twa[k]:
               twa1 = k
        for k in range(len(self.twa) - 1, 0, -1):
            if twa <= self.twa[k]:
                twa2 = k

        speed1 = self.speedTable[twa1][tws1]
        speed2 = self.speedTable[twa2][tws1]
        speed3 = self.speedTable[twa1][tws2]
        speed4 = self.speedTable[twa2][tws2]

        if twa1 != twa2:
            speed12 = speed1 + (speed2 - speed1) * (twa-self.twa[twa1]) / (self.twa[twa2] - self.twa[twa1])#interpolazione su twa
            speed34 = speed3 + (speed4 - speed3) * (twa-self.twa[twa1]) / (self.twa[twa2] - self.twa[twa1])#interpolazione su twa
        else:
            speed12 = speed1
            speed34 = speed3
        if tws1 != tws2:
            speed = speed12 + (speed34 - speed12) * (tws - self.tws[tws1]) / (self.tws[tws2] - self.tws[tws1])
        else:
            speed = speed12
        return speed
        

    def getReaching(self, tws: float) -> Tuple[float, float]:
        maxspeed = 0
        twamaxspeed = 0
        for twa in range(0,181):
            twa = math.radians(twa)
            speed = self.getSpeed (tws,twa)
            if speed > maxspeed:
                maxspeed = speed
                twamaxspeed = twa
        return (maxspeed, twamaxspeed)


    def getMaxVMGTWA(self, tws: float, twa: float) -> Tuple[float, float]:
        if not ((tws, twa) in self.vmgdict):
            twamin = max(0, twa-math.pi/2)
            twamax = min(math.pi, twa+math.pi/2)
            alfa = twamin
            maxvmg = -1.0
            while alfa < twamax:
                v = self.getSpeed (tws, alfa)
                vmg = v * math.cos(alfa-twa)
                if vmg - maxvmg > 10**-3:#10**-3 errore tollerato 
                    maxvmg = vmg
                    twamaxvmg = alfa
                alfa = alfa + math.radians(1)
            self.vmgdict[tws, twa] = (maxvmg, twamaxvmg)
        return self.vmgdict[(tws, twa)]


    def getMaxVMGUp(self, tws: float) -> Tuple[float, float]:
        vmguptupla = self.getMaxVMGTWA(tws, 0)
        return (vmguptupla[0], vmguptupla[1])


    def getMaxVMGDown(self, tws: float) -> Tuple[float, float]:
        vmgdowntupla = self.getMaxVMGTWA(tws, math.pi)
        return (-vmgdowntupla[0], vmgdowntupla[1])


    def getRoutageSpeed(self, tws, twa) -> float:
        UP = self.getMaxVMGUp(tws)
        vmgup = UP[0]
        twaup = UP[1]
        DOWN = self.getMaxVMGDown(tws)
        vmgdown = DOWN[0]
        twadown = DOWN[1]
        v = 0.0

        if twa >= twaup and twa <= twadown:
            v = self.getSpeed (tws, twa)
        else:
            if twa < twaup:
                v = vmgup / math.cos(twa)
            if twa > twadown:
                v = vmgdown / math.cos(twa)
        return v


    def getTWARoutage(self, tws: float, twa: float) -> float:
        UP = self.getMaxVMGUp(tws)
        vmgup = UP[0]
        twaup = UP[1]
        DOWN = self.getMaxVMGDown(tws)
        vmgdown = DOWN[0]
        twadown = DOWN[1]
        if twa >= twaup and twa <= twadown:
            twa = twa
        else:
            if twa < twaup:
                twa = twaup
            if twa > twadown:
                twa = twadown
        return twa

        