"""
/***************************************************************************
 SeilaplanPlugin
                                 A QGIS plugin
 Seillinien-Layoutplaner
                              -------------------
        begin                : 2013
        copyright            : (C) 2015 by ETH Zürich
        email                : seilaplanplugin@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import numpy as np

from SEILAPLAN.core.cableline_final import preciseCable
from SEILAPLAN.core.main_opti import optimization
from SEILAPLAN.core.terrain_analysis import stuePos
from SEILAPLAN.tools.config_handler_project import ProjectConfHandler
from SEILAPLAN.tools.globals import PolesOrigin, ResultQuality


def main(progress, project):
    """
    :type progress: processingThread.ProcessingTask
    :type project: projectHandler.ProjectConfHandler
    """
    project: ProjectConfHandler

    if progress.isCanceled():
        return False

    params = project.params.getSimpleParameterDict()
    profile = project.profile
    poles = project.poles

    # Search suitable pole positions along profile
    # TODO: Refactor into profile Class
    gp, StuetzenPos, diIdx, R_R = stuePos(
        params, profile, project.noPoleSection, project.fixedPoles
    )

    # Extend params dictionary TODO: better solution?
    params["R_R"] = R_R
    params["Ank"] = poles.anchor

    out = optimization(
        params,
        profile,
        StuetzenPos,
        progress,
        project.fixedPoles,
        [project.A_type, project.E_type],
    )
    if not out:
        if not progress.isCanceled():
            progress.exception = "Fehler in Optimierungsalgorithmus."
        return False

    progress.sig_text.emit("msg_seillinie")
    [HM, HMidx, optValue, optSTA, optiLen] = out

    project.params.setOptSTA(optSTA[0])

    stuetzDist = np.int32(diIdx[HMidx])

    # Check result status
    if not HMidx or HMidx == [0]:
        # Not a single pole location was calculated, no cable line possible
        progress.exception = "Aufgrund der Gelaendeform oder der Eingabeparameter konnten keine Stuetzenstandorte bestimmt werden."
        return False
    # Corresponds last optimized pole with end point?
    if int(poles.lastPole["d"]) != int(stuetzDist[-1]):
        # It was not possible to calculate poles along the entire profile
        progress.status.append(ResultQuality.LineNotComplete)

    # Save optimized poles to Pole() object
    optiPoles = []
    for idx, d in enumerate(stuetzDist):
        name = ""
        # Check if this is a fixed pole
        for fPole in project.fixedPoles["poles"]:
            if d == fPole["d"]:
                name = fPole["name"]
        optiPoles.append({"d": d, "h": HM[idx], "name": name})
    poles.updateAllPoles(PolesOrigin.Optimization, optiPoles)

    # Calculate precise cable line data
    cableline, force, seil_possible = preciseCable(params, poles, optSTA[0])
    if not seil_possible:
        # Cable is lifting off the poles
        progress.status.append(ResultQuality.CableLiftsOff)
    else:
        progress.status.append(ResultQuality.SuccessfulOptimization)

    progress.sig_value.emit(optiLen * 1.005)
    return {
        "cableline": cableline,
        "optSTA": optSTA[0],
        "optSTA_arr": optSTA,
        "force": force,
        "optLen": optiLen,
    }
