import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import QtQuick.Controls.Styles 1.3
import org.ethereum.qml.QEther 1.0
import "js/QEtherHelper.js" as QEtherHelper
import "js/TransactionHelper.js" as TransactionHelper
import "."

Dialog {
	id: modalStateDialog
	modality: Qt.ApplicationModal

	width: 630
	height: 660
	title: qsTr("Edit State")
	visible: false

	property alias stateTitle: titleField.text
	property alias isDefault: defaultCheckBox.checked
	property alias model: transactionsModel
	property alias transactionDialog: transactionDialog
	property alias minerComboBox: comboMiner
	property alias newAccAction: newAccountAction
	property int stateIndex
	property var stateTransactions: []
	property var stateAccounts: []
	property var stateContracts: []
	signal accepted

	StateDialogStyle {
		id: stateDialogStyle
	}

	function open(index, item, setDefault) {
		stateIndex = index
		stateTitle = item.title
		transactionsModel.clear()

		stateTransactions = []
		var transactions = item.transactions
		for (var t = 0; t < transactions.length; t++) {
			transactionsModel.append(item.transactions[t])
			stateTransactions.push(item.transactions[t])
		}

		accountsModel.clear()
		stateAccounts = []
		var miner = 0
		for (var k = 0; k < item.accounts.length; k++) {
			accountsModel.append(item.accounts[k])
			stateAccounts.push(item.accounts[k])
			if (item.miner && item.accounts[k].name === item.miner.name)
				miner = k
		}

		stateContracts = []
		if (item.contracts) {
			for (k = 0; k < item.contracts.length; k++) {
				contractsModel.append(item.contracts[k])
				stateContracts.push(item.contracts[k])
			}
		}

		visible = true
		isDefault = setDefault
		titleField.focus = true
		defaultCheckBox.enabled = !isDefault
		comboMiner.model = stateAccounts
		comboMiner.currentIndex = miner
		forceActiveFocus()
	}

	function acceptAndClose() {
		close()
		accepted()
	}

	function close() {
		visible = false
	}

	function getItem() {
		var item = {
			title: stateDialog.stateTitle,
			transactions: stateTransactions,
			accounts: stateAccounts,
			contracts: stateContracts
		}
		for (var k = 0; k < stateAccounts.length; k++) {
			if (stateAccounts[k].name === comboMiner.currentText) {
				item.miner = stateAccounts[k]
				break
			}
		}
		return item
	}

	contentItem: Rectangle {
		color: stateDialogStyle.generic.backgroundColor
		Rectangle {
			color: stateDialogStyle.generic.backgroundColor
			anchors.top: parent.top
			anchors.margins: 10
			anchors.fill: parent
			ColumnLayout {
				anchors.fill: parent
				anchors.margins: 10
				ColumnLayout {
					id: dialogContent
					anchors.top: parent.top
					RowLayout {
						Layout.fillWidth: true
						DefaultLabel {
							Layout.preferredWidth: 85
							text: qsTr("Title")
						}
						DefaultTextField {
							id: titleField
							Layout.fillWidth: true
						}
					}

					CommonSeparator {
						Layout.fillWidth: true
					}

					RowLayout {
						Layout.fillWidth: true

						Rectangle {
							Layout.preferredWidth: 85
							DefaultLabel {
								id: contractsLabel
								Layout.preferredWidth: 85
								wrapMode: Text.WrapAnywhere
								text: qsTr("Genesis\nContracts")
							}

							Button {
								id: importStateButton
								anchors.top: contractsLabel.bottom
								anchors.topMargin: 10
								action: importStateAction
							}

							Action {
								id: importStateAction
								tooltip: qsTr("Import genesis state from JSON file")
								text: qsTr("Import...")
								onTriggered: {
									importJsonFileDialog.open()
								}
							}
							FileDialog {
								id: importJsonFileDialog
								visible: false
								title: qsTr("Select State File")
								nameFilters: Qt.platform.os === "osx" ? [] : [qsTr("JSON files (*.json)", "All files (*)")] //qt 5.4 segfaults with filter string on OSX
								onAccepted: {
									var path = importJsonFileDialog.fileUrl.toString()
									var jsonData = fileIo.readFile(path)
									if (jsonData) {
										var json = JSON.parse(jsonData)
										for (var address in json) {
											var account = {
												address: address,
												name: (json[address].name ? json[address].name : address),
												balance: QEtherHelper.createEther(json[address].wei, QEther.Wei),
												code: json[address].code,
												storage: json[address].storage
											}
											if (account.code) {
												contractsModel.append(account)
												stateContracts.push(account)
											} else {
												accountsModel.append(account)
												stateAccounts.push(account)
											}
										}
									}
								}
							}
						}

						TableView {
							id: genesisContractsView
							Layout.fillWidth: true
							model: contractsModel
							headerVisible: false
							TableViewColumn {
								role: "name"
								title: qsTr("Name")
								width: 230
								delegate: Item {
									RowLayout {
										height: 25
										width: parent.width
										anchors.verticalCenter: parent.verticalCenter
										Button {
											iconSource: "qrc:/qml/img/delete_sign.png"
											action: deleteContractAction
										}

										Action {
											id: deleteContractAction
											tooltip: qsTr("Delete Contract")
											onTriggered: {
												stateContracts.splice(styleData.row, 1)
												contractsModel.remove(styleData.row)
											}
										}

										DefaultTextField {
											anchors.verticalCenter: parent.verticalCenter
											onTextChanged: {
												if (styleData.row > -1)
													stateContracts[styleData.row].name = text
											}
											text: styleData.value
										}
									}
								}
							}

							TableViewColumn {
								role: "balance"
								title: qsTr("Balance")
								width: 200
								delegate: Item {
									Ether {
										edit: true
										displayFormattedValue: false
										value: styleData.value
									}
								}
							}
							rowDelegate: Rectangle {
								color: styleData.alternate ? "transparent" : "#f0f0f0"
								height: 30
							}
						}
					}

					CommonSeparator {
						Layout.fillWidth: true
					}

					RowLayout {
						Layout.fillWidth: true

						Rectangle {
							Layout.preferredWidth: 85
							DefaultLabel {
								id: accountsLabel
								Layout.preferredWidth: 85
								text: qsTr("Accounts")
							}

							Button {
								id: newAccountButton
								anchors.top: accountsLabel.bottom
								anchors.topMargin: 10
								iconSource: "qrc:/qml/img/plus.png"
								action: newAccountAction
							}

							Action {
								id: newAccountAction
								tooltip: qsTr("Add new Account")
								onTriggered: {
									add()
								}

								function add() {
									var account = stateListModel.newAccount(
												"1000000", QEther.Ether)
									stateAccounts.push(account)
									accountsModel.append(account)
									return account
								}
							}
						}

						MessageDialog {
							id: alertAlreadyUsed
							text: qsTr("This account is in use. You cannot remove it. The first account is used to deploy config contract and cannot be removed.")
							icon: StandardIcon.Warning
							standardButtons: StandardButton.Ok
						}

						TableView {
							id: accountsView
							Layout.fillWidth: true
							model: accountsModel
							headerVisible: false
							TableViewColumn {
								role: "name"
								title: qsTr("Name")
								width: 230
								delegate: Item {
									RowLayout {
										height: 25
										width: parent.width
										Button {
											iconSource: "qrc:/qml/img/delete_sign.png"
											action: deleteAccountAction
										}

										Action {
											id: deleteAccountAction
											tooltip: qsTr("Delete Account")
											onTriggered: {
												if (transactionsModel.isUsed(
															stateAccounts[styleData.row].secret))
													alertAlreadyUsed.open()
												else {
													if (stateAccounts[styleData.row].name
															=== comboMiner.currentText)
														comboMiner.currentIndex = 0
													stateAccounts.splice(
																styleData.row,
																1)
													accountsModel.remove(
																styleData.row)
													comboMiner.model = stateAccounts //TODO: filter accounts wo private keys
													comboMiner.update()
												}
											}
										}

										DefaultTextField {
											anchors.verticalCenter: parent.verticalCenter
											onTextChanged: {
												if (styleData.row > -1) {
													stateAccounts[styleData.row].name = text
													var index = comboMiner.currentIndex
													comboMiner.model = stateAccounts
													comboMiner.currentIndex = index
												}
											}
											text: {
												return styleData.value
											}
										}
									}
								}
							}

							TableViewColumn {
								role: "balance"
								title: qsTr("Balance")
								width: 200
								delegate: Item {
									Ether {
										edit: true
										displayFormattedValue: false
										value: styleData.value
									}
								}
							}
							rowDelegate: Rectangle {
								color: styleData.alternate ? "transparent" : "#f0f0f0"
								height: 30
							}
						}
					}

					CommonSeparator {
						Layout.fillWidth: true
					}

					RowLayout {
						Layout.fillWidth: true
						DefaultLabel {
							Layout.preferredWidth: 85
							text: qsTr("Miner")
						}
						ComboBox {
							id: comboMiner
							textRole: "name"
							Layout.fillWidth: true
						}
					}

					CommonSeparator {
						Layout.fillWidth: true
					}

					RowLayout {
						Layout.fillWidth: true
						DefaultLabel {
							Layout.preferredWidth: 85
							text: qsTr("Default")
						}
						CheckBox {
							id: defaultCheckBox
							Layout.fillWidth: true
						}
					}

					CommonSeparator {
						Layout.fillWidth: true
					}

					RowLayout {
						Layout.fillWidth: true

						Rectangle {
							Layout.preferredWidth: 85
							DefaultLabel {
								id: transactionsLabel
								Layout.preferredWidth: 85
								text: qsTr("Transactions")
							}

							Button {
								anchors.top: transactionsLabel.bottom
								anchors.topMargin: 10
								iconSource: "qrc:/qml/img/plus.png"
								action: newTrAction
							}

							Action {
								id: newTrAction
								tooltip: qsTr("Create a new transaction")
								onTriggered: transactionsModel.addTransaction()
							}
						}

						TableView {
							id: transactionsView
							Layout.fillWidth: true
							model: transactionsModel
							headerVisible: false
							TableViewColumn {
								role: "label"
								title: qsTr("Name")
								width: 150
								delegate: Item {
									RowLayout {
										height: 30
										width: parent.width
										Button {
											iconSource: "qrc:/qml/img/delete_sign.png"
											action: deleteTransactionAction
										}

										Action {
											id: deleteTransactionAction
											tooltip: qsTr("Delete")
											onTriggered: transactionsModel.deleteTransaction(
															 styleData.row)
										}

										Button {
											iconSource: "qrc:/qml/img/edit.png"
											action: editAction
											visible: styleData.row
													 >= 0 ? !transactionsModel.get(
																styleData.row).stdContract : false
											width: 10
											height: 10
											Action {
												id: editAction
												tooltip: qsTr("Edit")
												onTriggered: transactionsModel.editTransaction(
																 styleData.row)
											}
										}

										DefaultLabel {
											Layout.preferredWidth: 150
											text: {
												if (styleData.row >= 0)
													return transactionsModel.get(
																styleData.row).label
												else
													return ""
											}
										}
									}
								}
							}
							rowDelegate: Rectangle {
								color: styleData.alternate ? "transparent" : "#f0f0f0"
								height: 30
							}
						}
					}
				}

				RowLayout {
					anchors.bottom: parent.bottom
					anchors.right: parent.right

					Button {
						text: qsTr("Delete")
						enabled: !modalStateDialog.isDefault
						onClicked: {
							projectModel.stateListModel.deleteState(stateIndex)
							close()
						}
					}
					Button {
						text: qsTr("OK")
						onClicked: {
							if (titleField.text === "")
								alertDialog.open()
							else
							{
								close()
								accepted()
							}
						}
					}
					Button {
						text: qsTr("Cancel")
						onClicked: close()
					}
				}

				MessageDialog
				{
					id: alertDialog
					text: qsTr("Please provide a name.")
				}

				ListModel {
					id: accountsModel

					function removeAccount(_i) {
						accountsModel.remove(_i)
						stateAccounts.splice(_i, 1)
					}
				}

				ListModel {
					id: contractsModel

					function removeContract(_i) {
						contractsModel.remove(_i)
						stateContracts.splice(_i, 1)
					}
				}

				ListModel {
					id: transactionsModel

					function editTransaction(index) {
						transactionDialog.stateAccounts = stateAccounts
						transactionDialog.open(index,
											   transactionsModel.get(index))
					}

					function addTransaction() {
						// Set next id here to work around Qt bug
						// https://bugreports.qt-project.org/browse/QTBUG-41327
						// Second call to signal handler would just edit the item that was just created, no harm done
						var item = TransactionHelper.defaultTransaction()
						transactionDialog.stateAccounts = stateAccounts
						transactionDialog.open(transactionsModel.count, item)
					}

					function deleteTransaction(index) {
						stateTransactions.splice(index, 1)
						transactionsModel.remove(index)
					}

					function isUsed(secret) {
						for (var i in stateTransactions) {
							if (stateTransactions[i].sender === secret)
								return true
						}
						return false
					}
				}

				TransactionDialog {
					id: transactionDialog
					onAccepted: {
						var item = transactionDialog.getItem()
						if (transactionDialog.transactionIndex < transactionsModel.count) {
							transactionsModel.set(
										transactionDialog.transactionIndex,
										item)
							stateTransactions[transactionDialog.transactionIndex] = item
						} else {
							transactionsModel.append(item)
							stateTransactions.push(item)
						}
					}
				}
			}
		}
	}
}