# -*- coding: utf-8 -*-
# Roastero, released under GPLv3

import os
import json
import time
import functools

from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5 import QtWidgets

from openroast import tools
from openroast.views import customqtwidgets
from openroast import utils as utils

class RecipeEditor(QtWidgets.QDialog):
    def __init__(self, recipeLocation=None):
        super(RecipeEditor, self).__init__()

        # Define main window for the application.
        self.setWindowTitle('Openroast')
        self.setMinimumSize(800, 600)
        self.setContextMenuPolicy(QtCore.Qt.NoContextMenu)

        self.create_ui()

        self.recipe = {}
        self.recipe["steps"] = [{'fanSpeed': 5, 'targetTemp': 150,
            'sectionTime': 0}]

        if recipeLocation:
            self.load_recipe_file(recipeLocation)
            self.preload_recipe_information()
        else:
            self.preload_recipe_steps(self.recipeSteps)

    def create_ui(self):
        """A method used to create the basic ui for the Recipe Editor Window"""
        # Create main layout for window.
        self.layout = QtWidgets.QGridLayout(self)
        self.layout.setRowStretch(1, 3)

        # Create input fields.
        self.create_input_fields()
        self.layout.addLayout(self.inputFieldLayout, 0, 0, 1, 2)

        # Create big edit boxes.
        self.create_big_edit_boxes()
        self.layout.addLayout(self.bigEditLayout, 1, 0, 1, 2)

        # Create Bottom Buttons.
        self.create_bottom_buttons()
        self.layout.addLayout(self.bottomButtonLayout, 2, 0, 1, 2)


    def create_input_fields(self):
        """Creates all of the UI components for the top of the Recipe Editor
        Window."""
        # Create layout for section.
        self.inputFieldLayout = QtWidgets.QGridLayout()

        # Create labels for fields.
        recipeNameLabel = QtWidgets.QLabel("Recipe Name: ")
        recipeCreatorLabel = QtWidgets.QLabel("Created by: ")
        recipeRoastTypeLabel = QtWidgets.QLabel("Roast Type: ")
        beanRegionLabel = QtWidgets.QLabel("Bean Region: ")
        beanCountryLabel = QtWidgets.QLabel("Bean Country: ")
        beanLinkLabel = QtWidgets.QLabel("Bean Link: ")
        beanStoreLabel = QtWidgets.QLabel("Bean Store Name: ")

        # Create input fields.
        self.recipeName = QtWidgets.QLineEdit()
        self.recipeCreator = QtWidgets.QLineEdit()
        self.recipeRoastType = QtWidgets.QLineEdit()
        self.beanRegion = QtWidgets.QLineEdit()
        self.beanCountry = QtWidgets.QLineEdit()
        self.beanLink = QtWidgets.QLineEdit()
        self.beanStore = QtWidgets.QLineEdit()

        # Remove focus from input boxes.
        self.recipeName.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
        self.recipeCreator.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
        self.recipeRoastType.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
        self.beanRegion.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
        self.beanCountry.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
        self.beanLink.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
        self.beanStore.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)

        # Add objects to the inputFieldLayout
        self.inputFieldLayout.addWidget(recipeNameLabel, 0, 0)
        self.inputFieldLayout.addWidget(self.recipeName, 0, 1)
        self.inputFieldLayout.addWidget(recipeCreatorLabel, 1, 0)
        self.inputFieldLayout.addWidget(self.recipeCreator, 1, 1)
        self.inputFieldLayout.addWidget(recipeRoastTypeLabel, 2, 0)
        self.inputFieldLayout.addWidget(self.recipeRoastType, 2, 1)
        self.inputFieldLayout.addWidget(beanRegionLabel, 3, 0)
        self.inputFieldLayout.addWidget(self.beanRegion, 3, 1)
        self.inputFieldLayout.addWidget(beanCountryLabel, 4, 0)
        self.inputFieldLayout.addWidget(self.beanCountry, 4, 1)
        self.inputFieldLayout.addWidget(beanLinkLabel, 5, 0)
        self.inputFieldLayout.addWidget(self.beanLink, 5, 1)
        self.inputFieldLayout.addWidget(beanStoreLabel, 6, 0)
        self.inputFieldLayout.addWidget(self.beanStore, 6, 1)

    def create_big_edit_boxes(self):
        """Creates the Bottom section of the Recipe Editor Window. This method
        creates the Description box and calls another method to make the
        recipe steps table."""
        # Create big edit box layout.
        self.bigEditLayout = QtWidgets.QGridLayout()

        # Create labels for the edit boxes.
        recipeDescriptionBoxLabel = QtWidgets.QLabel("Description: ")
        recipeStepsLabel = QtWidgets.QLabel("Steps: ")

        # Create widgets.
        self.recipeDescriptionBox = QtWidgets.QTextEdit()
        self.recipeSteps = self.create_steps_spreadsheet()

        # Add widgets to layout.
        self.bigEditLayout.addWidget(recipeDescriptionBoxLabel, 0, 0)
        self.bigEditLayout.addWidget(self.recipeDescriptionBox, 1, 0)
        self.bigEditLayout.addWidget(recipeStepsLabel, 0, 1)
        self.bigEditLayout.addWidget(self.recipeSteps, 1, 1)

    def create_bottom_buttons(self):
        """Creates the button panel on the bottom of the Recipe Editor
        Window."""
        # Set bottom button layout.
        self.bottomButtonLayout = QtWidgets.QHBoxLayout()
        self.bottomButtonLayout.setSpacing(0)

        # Create buttons.
        self.saveButton = QtWidgets.QPushButton("SAVE")
        self.closeButton = QtWidgets.QPushButton("CLOSE")

        # Assign object names to the buttons.
        self.saveButton.setObjectName("smallButton")
        self.saveButton.clicked.connect(self.save_recipe)
        self.closeButton.setObjectName("smallButton")
        self.closeButton.clicked.connect(self.close_edit_window)

        # Create Spacer.
        self.spacer = QtWidgets.QWidget()
        self.spacer.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)

        # Add widgets to the layout.
        self.bottomButtonLayout.addWidget(self.spacer)
        self.bottomButtonLayout.addWidget(self.closeButton)
        self.bottomButtonLayout.addWidget(self.saveButton)

    def create_steps_spreadsheet(self):
        """Creates Recipe Steps table. It does not populate the table in this
        method."""
        recipeStepsTable = QtWidgets.QTableWidget()
        recipeStepsTable.setShowGrid(False)
        recipeStepsTable.setAlternatingRowColors(True)
        recipeStepsTable.setCornerButtonEnabled(False)
        recipeStepsTable.horizontalHeader().setSectionResizeMode(1)
        recipeStepsTable.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)

        # Steps spreadsheet
        recipeStepsTable.setColumnCount(4)
        recipeStepsTable.setHorizontalHeaderLabels(["Temperature",
            "Fan Speed", "Section Time", "Modify"])

        return recipeStepsTable

    def close_edit_window(self):
        """Method used to close the Recipe Editor Window."""
        self.close()

    def preload_recipe_steps(self, recipeStepsTable):
        """Method that just calls load_recipe_steps() with a table specified and
        uses the pre-existing loaded recipe steps in the object."""
        steps = self.recipe["steps"]
        self.load_recipe_steps(recipeStepsTable, steps)

    def load_recipe_steps(self, recipeStepsTable, steps):
        """Takes two arguments. One being the table and the second being the
        rows you'd like to add. It does not clear the table and simply adds the
        rows on the bottom if there are exiting rows."""
        # Create spreadsheet choices
        fanSpeedChoices = [str(x) for x in range(1,10)]
        targetTempChoices = ["Cooling"] + [str(x) for x in range(150, 551, 10)]

        # loop through recipe and load each step
        for row in range(len(steps)):
            recipeStepsTable.insertRow(recipeStepsTable.rowCount())
            # Temperature Value
            sectionTempWidget = customqtwidgets.ComboBoxNoWheel()
            sectionTempWidget.setObjectName("recipeEditCombo")
            sectionTempWidget.addItems(targetTempChoices)
            sectionTempWidget.insertSeparator(1)

            if 'targetTemp' in steps[row]:
                sectionTemp = steps[row]["targetTemp"]
                # Accommodate for temperature not fitting in 10 increment list
                if str(steps[row]["targetTemp"]) in targetTempChoices:
                    sectionTempWidget.setCurrentIndex(
                        targetTempChoices.index(
                        str(steps[row]["targetTemp"]))+1)
                else:
                    roundedNumber = steps[row]["targetTemp"] - (steps[row]["targetTemp"] % 10)
                    sectionTempWidget.insertItem(targetTempChoices.index(str(roundedNumber))+2, str(steps[row]["targetTemp"]))
                    sectionTempWidget.setCurrentIndex(targetTempChoices.index(str(roundedNumber))+2)

            elif 'cooling' in steps[row]:
                sectionTemp = "Cooling"
                sectionTempWidget.setCurrentIndex(targetTempChoices.index("Cooling"))


            # Time Value
            sectionTimeWidget = customqtwidgets.TimeEditNoWheel()
            sectionTimeWidget.setObjectName("recipeEditTime")
            sectionTimeWidget.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 0)
            sectionTimeWidget.setDisplayFormat("mm:ss")
            # Set QTimeEdit to the right time from recipe
            sectionTimeStr = time.strftime("%M:%S", time.gmtime(steps[row]["sectionTime"]))
            sectionTime = QtCore.QTime().fromString(sectionTimeStr, "mm:ss")
            sectionTimeWidget.setTime(sectionTime)

            # Fan Speed Value
            sectionFanSpeedWidget = customqtwidgets.ComboBoxNoWheel()
            sectionFanSpeedWidget.setObjectName("recipeEditCombo")

            sectionFanSpeedWidget.addItems(fanSpeedChoices)
            sectionFanSpeedWidget.setCurrentIndex(fanSpeedChoices.index(str(steps[row]["fanSpeed"])))

            # Modify Row field
            upArrow = QtWidgets.QPushButton()
            upArrow.setObjectName("upArrow")
            #upArrow.setIcon(QtGui.QIcon('static/images/upSmall.png'))
            upArrow.setIcon(
                QtGui.QIcon(
                    utils.get_resource_filename(
                        'static/images/upSmall.png'
                    )
                )
            )
            upArrow.clicked.connect(functools.partial(self.move_recipe_step_up, row))
            downArrow = QtWidgets.QPushButton()
            downArrow.setObjectName("downArrow")
            #downArrow.setIcon(QtGui.QIcon('static/images/downSmall.png'))
            downArrow.setIcon(
                QtGui.QIcon(
                    utils.get_resource_filename(
                        'static/images/downSmall.png'
                    )
                )
            )
            downArrow.clicked.connect(functools.partial(self.move_recipe_step_down, row))
            deleteRow = QtWidgets.QPushButton()
            # deleteRow.setIcon(QtGui.QIcon('static/images/delete.png'))
            deleteRow.setIcon(
                QtGui.QIcon(
                    utils.get_resource_filename(
                        'static/images/delete.png'
                    )
                )
            )
            deleteRow.setObjectName("deleteRow")
            deleteRow.clicked.connect(functools.partial(self.delete_recipe_step, row))
            insertRow = QtWidgets.QPushButton()
            # insertRow.setIcon(QtGui.QIcon('static/images/plus.png'))
            insertRow.setIcon(
                QtGui.QIcon(
                    utils.get_resource_filename(
                        'static/images/plus.png'
                    )
                )
            )
            insertRow.setObjectName("insertRow")
            insertRow.clicked.connect(functools.partial(self.insert_recipe_step, row))

            # Create a grid layout to add all the widgets to
            modifyRowWidgetLayout = QtWidgets.QHBoxLayout()
            modifyRowWidgetLayout.setSpacing(0)
            modifyRowWidgetLayout.setContentsMargins(0,0,0,0)
            modifyRowWidgetLayout.addWidget(upArrow)
            modifyRowWidgetLayout.addWidget(downArrow)
            modifyRowWidgetLayout.addWidget(deleteRow)
            modifyRowWidgetLayout.addWidget(insertRow)

            # Assign Layout to a QWidget to add to a single column
            modifyRowWidget = QtWidgets.QWidget()
            modifyRowWidget.setObjectName("buttonTable")
            modifyRowWidget.setLayout(modifyRowWidgetLayout)

            # Add widgets
            recipeStepsTable.setCellWidget(row, 0, sectionTempWidget)
            recipeStepsTable.setCellWidget(row, 1, sectionFanSpeedWidget)
            recipeStepsTable.setCellWidget(row, 2, sectionTimeWidget)
            recipeStepsTable.setCellWidget(row, 3, modifyRowWidget)

    def load_recipe_file(self, recipeFile):
        """Takes a file location and opens that file. It then loads the contents
        which should be JSON and makes a python dictionary from the contents.
        The python dictionary is created as self.recipe."""
        # Load recipe file
        recipeFileHandler = open(recipeFile)
        self.recipe = json.load(recipeFileHandler)
        self.recipe["file"] = recipeFile
        recipeFileHandler.close()

    def preload_recipe_information(self):
        """Loads information from self.recipe and prefills all the fields in the
        form."""
        self.recipeName.setText(self.recipe["roastName"])
        self.recipeCreator.setText(self.recipe["creator"])
        self.recipeRoastType.setText(self.recipe["roastDescription"]["roastType"])
        self.beanRegion.setText(self.recipe["bean"]["region"])
        self.beanCountry.setText(self.recipe["bean"]["country"])
        self.beanLink.setText(self.recipe["bean"]["source"]["link"])
        self.beanStore.setText(self.recipe["bean"]["source"]["reseller"])
        self.recipeDescriptionBox.setText(self.recipe["roastDescription"]["description"])

        self.preload_recipe_steps(self.recipeSteps)

    def move_recipe_step_up(self, row):
        """This method will take a row and swap it the row above it."""
        if row != 0:
            steps = self.get_current_table_values()
            newSteps = steps

            # Swap the steps
            newSteps[row], newSteps[row-1] = newSteps[row-1], newSteps[row]

            # Rebuild table with new steps
            self.rebuild_recipe_steps_table(newSteps)

    def move_recipe_step_down(self, row):
        """This method will take a row and swap it the row below it."""
        if row != self.recipeSteps.rowCount()-1:
            steps = self.get_current_table_values()
            newSteps = steps

            # Swap the steps
            newSteps[row], newSteps[row+1] = newSteps[row+1], newSteps[row]

            # Rebuild table with new steps
            self.rebuild_recipe_steps_table(newSteps)

    def delete_recipe_step(self, row):
        """This method will take a row delete it."""
        steps = self.get_current_table_values()
        newSteps = steps

        # Delete step
        newSteps.pop(row)

        # Rebuild table with new steps
        self.rebuild_recipe_steps_table(newSteps)

    def insert_recipe_step(self, row):
        """Inserts a row below the specified row wit generic values."""
        steps = self.get_current_table_values()
        newSteps = steps

        # insert step
        newSteps.insert(row+1, {'fanSpeed': 5, 'targetTemp': 150, 'sectionTime': 0})

        # Rebuild table with new steps
        self.rebuild_recipe_steps_table(newSteps)

    def get_current_table_values(self):
        """Used to read all the current table values from the recipeSteps table
        and build a dictionary of all the values."""
        recipeSteps = []
        for row in range(0, self.recipeSteps.rowCount()):
            currentRow = {}
            currentRow["sectionTime"] = QtCore.QTime(0, 0, 0).secsTo(self.recipeSteps.cellWidget(row, 2).time())
            currentRow["fanSpeed"] = int(self.recipeSteps.cellWidget(row, 1).currentText())

            # Get Temperature or cooling
            if self.recipeSteps.cellWidget(row, 0).currentText() == "Cooling":
                currentRow["cooling"] = True
            else:
                currentRow["targetTemp"] = int(self.recipeSteps.cellWidget(row, 0).currentText())

            recipeSteps.append(currentRow)

        # Return copied rows
        return recipeSteps

    def rebuild_recipe_steps_table(self, newSteps):
        """Used to reload all the rows in the recipe steps table with new steps.
        """
        # Alert user if they try to delete all the steps
        if len(newSteps) < 1:
            alert = QtWidgets.QMessageBox()
            alert.setWindowTitle('openroast')
            alert.setStyleSheet(self.style)
            alert.setText("You must have atleast one step!")
            alert.exec_()

        else:
            # Delete all the current rows
            while self.recipeSteps.rowCount() > 0:
                self.recipeSteps.removeRow(0)
            # Add the new step sequence
            self.load_recipe_steps(self.recipeSteps, newSteps)

    def save_recipe(self):
        """Pulls in all of the information in the window and creates a new
        recipe file with the specified contents."""
        # Determine Recipe File Name
        if "file" in self.recipe:
            filePath = self.recipe["file"]
        else:
            filePath = os.path.expanduser('~/Documents/Openroast/Recipes/My Recipes/') + tools.format_filename(self.recipeName.text()) + ".json"
            # TODO: Account for existing file with same name

        # Create Dictionary with all the new recipe information
        self.newRecipe = {}
        self.newRecipe["roastName"] = self.recipeName.text()
        self.newRecipe["steps"] = self.get_current_table_values()
        self.newRecipe["roastDescription"] = {}
        self.newRecipe["roastDescription"]["roastType"] = self.recipeRoastType.text()
        self.newRecipe["roastDescription"]["description"] = self.recipeDescriptionBox.toPlainText()
        self.newRecipe["creator"] = self.recipeCreator.text()
        self.newRecipe["bean"] = {}
        self.newRecipe["bean"]["region"] = self.beanRegion.text()
        self.newRecipe["bean"]["country"] = self.beanCountry.text()
        self.newRecipe["bean"]["source"] = {}
        self.newRecipe["bean"]["source"]["reseller"] = self.beanStore.text()
        self.newRecipe["bean"]["source"]["link"] = self.beanLink.text()
        self.newRecipe["totalTime"] = 0
        for step in self.newRecipe["steps"]:
            self.newRecipe["totalTime"] += step["sectionTime"]

        # Write the recipe to a file
        jsonObject = json.dumps(self.newRecipe, indent=4)
        # will need to create dir if it doesn't exist
        # note that this should never happen because this folder is created
        # at OpenroastApp.__init__() time.
        if not os.path.exists(os.path.dirname(filePath)):
            try:
                os.makedirs(os.path.dirname(filePath))
            except OSError as exc: # Guard against race condition
                if exc.errno != errno.EEXIST:
                    raise
        file = open(filePath, 'w')
        file.write(jsonObject)
        file.close()