#  NanoVNASaver
#
#  A python program to view and export Touchstone data from a NanoVNA
#  Copyright (C) 2019, 2020  Rune B. Broberg
#  Copyright (C) 2020,2021 NanoVNA-Saver Authors
#
#  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.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
import logging

from PyQt5 import QtWidgets, QtCore

from NanoVNASaver.Formatting import (
    format_frequency_sweep, format_frequency_short,
    parse_frequency)
from NanoVNASaver.Inputs import FrequencyInputWidget
from NanoVNASaver.Controls.Control import Control

logger = logging.getLogger(__name__)


class SweepControl(Control):

    def __init__(self, app: QtWidgets.QWidget):
        super().__init__(app, "Sweep control")

        line = QtWidgets.QFrame()
        line.setFrameShape(QtWidgets.QFrame.VLine)

        input_layout = QtWidgets.QHBoxLayout()
        input_left_layout = QtWidgets.QFormLayout()
        input_right_layout = QtWidgets.QFormLayout()
        input_layout.addLayout(input_left_layout)
        input_layout.addWidget(line)
        input_layout.addLayout(input_right_layout)
        self.layout.addRow(input_layout)

        self.input_start = FrequencyInputWidget()
        self.input_start.setFixedHeight(20)
        self.input_start.setMinimumWidth(60)
        self.input_start.setAlignment(QtCore.Qt.AlignRight)
        self.input_start.textEdited.connect(self.update_center_span)
        self.input_start.textChanged.connect(self.update_step_size)
        input_left_layout.addRow(QtWidgets.QLabel("Start"), self.input_start)

        self.input_end = FrequencyInputWidget()
        self.input_end.setFixedHeight(20)
        self.input_end.setAlignment(QtCore.Qt.AlignRight)
        self.input_end.textEdited.connect(self.update_center_span)
        self.input_end.textChanged.connect(self.update_step_size)
        input_left_layout.addRow(QtWidgets.QLabel("Stop"), self.input_end)

        self.input_center = FrequencyInputWidget()
        self.input_center.setFixedHeight(20)
        self.input_center.setMinimumWidth(60)
        self.input_center.setAlignment(QtCore.Qt.AlignRight)
        self.input_center.textEdited.connect(self.update_start_end)

        input_right_layout.addRow(QtWidgets.QLabel(
            "Center"), self.input_center)

        self.input_span = FrequencyInputWidget()
        self.input_span.setFixedHeight(20)
        self.input_span.setAlignment(QtCore.Qt.AlignRight)
        self.input_span.textEdited.connect(self.update_start_end)

        input_right_layout.addRow(QtWidgets.QLabel("Span"), self.input_span)

        self.input_segments = QtWidgets.QLineEdit(
            self.app.settings.value("Segments", "1"))
        self.input_segments.setAlignment(QtCore.Qt.AlignRight)
        self.input_segments.setFixedHeight(20)
        self.input_segments.setFixedWidth(60)
        self.input_segments.textEdited.connect(self.update_step_size)

        self.label_step = QtWidgets.QLabel("Hz/step")
        self.label_step.setAlignment(
            QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)

        segment_layout = QtWidgets.QHBoxLayout()
        segment_layout.addWidget(self.input_segments)
        segment_layout.addWidget(self.label_step)
        self.layout.addRow(QtWidgets.QLabel("Segments"), segment_layout)

        btn_settings_window = QtWidgets.QPushButton("Sweep settings ...")
        btn_settings_window.setFixedHeight(20)
        btn_settings_window.clicked.connect(
            lambda: self.app.display_window("sweep_settings"))

        self.layout.addRow(btn_settings_window)

        self.progress_bar = QtWidgets.QProgressBar()
        self.progress_bar.setMaximum(100)
        self.progress_bar.setValue(0)
        self.layout.addRow(self.progress_bar)

        self.btn_start = QtWidgets.QPushButton("Sweep")
        self.btn_start.setFixedHeight(20)
        self.btn_start.clicked.connect(self.app.sweep_start)
        self.btn_start.setShortcut(QtCore.Qt.Key_W | QtCore.Qt.CTRL)
        self.btn_stop = QtWidgets.QPushButton("Stop")
        self.btn_stop.setFixedHeight(20)
        self.btn_stop.clicked.connect(self.app.sweep_stop)
        self.btn_stop.setShortcut(QtCore.Qt.Key_Escape)
        self.btn_stop.setDisabled(True)
        btn_layout = QtWidgets.QHBoxLayout()
        btn_layout.addWidget(self.btn_start)
        btn_layout.addWidget(self.btn_stop)
        btn_layout.setContentsMargins(0, 0, 0, 0)
        btn_layout_widget = QtWidgets.QWidget()
        btn_layout_widget.setLayout(btn_layout)
        self.layout.addRow(btn_layout_widget)

        self.input_start.textEdited.emit(self.input_start.text())
        self.input_start.textChanged.emit(self.input_start.text())

    def get_start(self) -> int:
        return parse_frequency(self.input_start.text())

    def set_start(self, start: int):
        self.input_start.setText(format_frequency_sweep(start))
        self.input_start.textEdited.emit(self.input_start.text())
        self.updated.emit(self)

    def get_end(self) -> int:
        return parse_frequency(self.input_end.text())

    def set_end(self, end: int):
        self.input_end.setText(format_frequency_sweep(end))
        self.input_end.textEdited.emit(self.input_end.text())
        self.updated.emit(self)

    def get_center(self) -> int:
        return parse_frequency(self.input_center.text())

    def set_center(self, center: int):
        self.input_center.setText(format_frequency_sweep(center))
        self.input_center.textEdited.emit(self.input_center.text())
        self.updated.emit(self)

    def get_segments(self) -> int:
        try:
            result = int(self.input_segments.text())
        except ValueError:
            result = 1
        return result

    def set_segments(self, count: int):
        self.input_segments.setText(str(count))
        self.input_segments.textEdited.emit(self.input_segments.text())
        self.updated.emit(self)

    def get_span(self) -> int:
        return parse_frequency(self.input_span.text())

    def set_span(self, span: int):
        self.input_span.setText(format_frequency_sweep(span))
        self.input_span.textEdited.emit(self.input_span.text())
        self.updated.emit(self)

    def toggle_settings(self, disabled):
        self.input_start.setDisabled(disabled)
        self.input_end.setDisabled(disabled)
        self.input_span.setDisabled(disabled)
        self.input_center.setDisabled(disabled)
        self.input_segments.setDisabled(disabled)

    def update_center_span(self):
        fstart = self.get_start()
        fstop = self.get_end()
        fspan = fstop - fstart
        fcenter = round((fstart + fstop) / 2)
        if fspan < 0 or fstart < 0 or fstop < 0:
            return
        self.input_span.setText(fspan)
        self.input_center.setText(fcenter)
        self.update_sweep()

    def update_start_end(self):
        fcenter = self.get_center()
        fspan = self.get_span()
        if fspan < 0 or fcenter < 0:
            return
        fstart = round(fcenter - fspan / 2)
        fstop = round(fcenter + fspan / 2)
        if fstart < 0 or fstop < 0:
            return
        self.input_start.setText(fstart)
        self.input_end.setText(fstop)
        self.update_sweep()

    def update_step_size(self):
        fspan = self.get_span()
        if fspan < 0:
            return
        segments = self.get_segments()
        if segments > 0:
            fstep = fspan / (segments * self.app.vna.datapoints - 1)
            self.label_step.setText(
                f"{format_frequency_short(fstep)}/step")
        self.update_sweep()

    def update_sweep(self):
        sweep = self.app.sweep
        with sweep.lock:
            sweep.start = self.get_start()
            sweep.end = self.get_end()
            sweep.segments = self.get_segments()
            sweep.points = self.app.vna.datapoints
