import time, sys, os, configparser
from pyfasttext import FastText

from PyQt5.QtWidgets import (QVBoxLayout, QLineEdit,QGridLayout,
 QApplication, QLabel, QMenu, QWidget, QHBoxLayout,QDialog,
 QAction, QTextEdit,QPushButton, qApp, QMessageBox, QInputDialog,
 QMainWindow, QFrame, QFileDialog, QCheckBox, QProgressBar,
 QListWidget, QCompleter, QComboBox, QTreeView,QAbstractItemView,
 QToolTip,QRadioButton,QButtonGroup)
from PyQt5.QtGui import (QIcon, QFont, QColor, QPixmap, QDrag, QPainter,
 QBrush, QPen,QStandardItem,QStandardItemModel)
from PyQt5.QtCore import (QCoreApplication, Qt, QObject, pyqtSignal,
 QMimeData, QAbstractItemModel,QModelIndex)
from PyQt5 import QtCore

from word_count_window import count
from cognitive_result import Cognitive_map_result_SubWindow
from tsne import Pca, Tsne

class ListView(QListWidget):
    def __init__(self, *args, **kwargs):
        super(ListView, self).__init__(*args, **kwargs)

    def removeSelectedItem(self):
        model    = self.model()
        selModel = self.selectionModel()

        while True:
            indexes = selModel.selectedIndexes()
            if not indexes:
                break

            model.removeRow(indexes[0].row())

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Delete:
            self.removeSelectedItem()
            return

        super(ListView, self).keyPressEvent(event)

class Tsne_graph_SubWindow(QWidget):

    def __init__(self, project, model):
        super().__init__()
        self.project=project
        self.model = model
        self.selected_word = ""

        self.TSNE_window()

    def TSNE_window(self):
        self.w=QDialog()


        candidate_box=QHBoxLayout()

        radio_v_box = QVBoxLayout()
        radio_vv_box=QVBoxLayout()
        search_label=QLabel("使用可能な単語の検索")
        self.content_word = QRadioButton("内容語") #基本形を使用
        self.all_word = QRadioButton("全出現語")  #表層形を使用

        self.button_group = QButtonGroup()
        self.button_group.addButton(self.content_word)
        self.button_group.addButton(self.all_word)
        self.content_word.toggle()
        radio_vv_box.addWidget(self.content_word)
        radio_vv_box.addWidget(self.all_word)

        count_v_box = QVBoxLayout()
        text_label = QLabel("出現回数")
        self.min = QLineEdit()
        self.min.setToolTip("参照する単語の最低出現回数を設定してください")
        self.min.setText("5")
        co_h_box=QHBoxLayout()
        count_label = QLabel("回以上")
        co_h_box.addStretch(1)
        co_h_box.addWidget(count_label)
        count_v_box.addWidget(text_label)
        count_v_box.addStretch(2)
        count_v_box.addWidget(self.min)
        count_v_box.addLayout(co_h_box)

        search_button=QPushButton("検索")
        search_button.clicked.connect(self.search_word)

        radio_v_box.addStretch(3)
        radio_v_box.addWidget(search_label)
        radio_v_box.addStretch(1)
        radio_v_box.addLayout(radio_vv_box)
        radio_v_box.addStretch(1)
        radio_v_box.addLayout(count_v_box)
        radio_v_box.addStretch(1)
        radio_v_box.addWidget(search_button)
        radio_v_box.addStretch(3)

        word_a_box=QVBoxLayout()
        word_a_label=QLabel("プロットする単語")
        add_a_box=QHBoxLayout()
        self.add_word_a=QLineEdit()
        self.add_word_a.setToolTip("複数の単語を追加する場合は「スペース」で区切ってください")
        add_word_a_button=QPushButton("追加")
        add_word_a_button.clicked.connect(self.input_word_a)
        add_a_box.addWidget(self.add_word_a)
        add_a_box.addWidget(add_word_a_button)
        self.word_a_items=ListView()  #word_aはプロットする単語
        self.word_a_items.setSelectionMode(QAbstractItemView.ExtendedSelection)
        word_a_box.addWidget(word_a_label)
        word_a_box.addLayout(add_a_box)
        word_a_box.addWidget(self.word_a_items)
        self.word_a_items.itemSelectionChanged.connect(self.change_item_a)

        to_from_a_box=QVBoxLayout()
        to_word_a_button=QPushButton(">")
        to_word_a_button.clicked.connect(self.to_word_a)
        from_word_a_button=QPushButton("<")
        from_word_a_button.clicked.connect(self.from_word_a)
        to_from_a_box.addStretch(1)
        to_from_a_box.addWidget(to_word_a_button)
        to_from_a_box.addWidget(from_word_a_button)
        to_from_a_box.addStretch(1)

        candidate_v_box=QVBoxLayout()
        candidate_label=QLabel("候補の単語")
        self.candidate_word=QListWidget()    #candidate_wordは候補の単語
        self.candidate_word.setSelectionMode(QAbstractItemView.ExtendedSelection)   #複数選択を可能にする
        candidate_v_box.addWidget(candidate_label)
        candidate_v_box.addWidget(self.candidate_word)
        self.candidate_word.itemSelectionChanged.connect(self.change_item)

        variable_v_box = QVBoxLayout()

        perplexity_h_box = QHBoxLayout()
        perplexity_label = QLabel("perplexity")
        self.perplexity = QLineEdit()
        self.perplexity.setText("30")
        self.perplexity.setToolTip("5から50が推奨されています<br>プロットする単語数より少なく設定してください")
        perplexity_h_box.addWidget(perplexity_label)
        perplexity_h_box.addStretch(1)
        perplexity_h_box.addWidget(self.perplexity)


        learning_rate_h_box = QHBoxLayout()
        learning_rate_label = QLabel("学習率")
        self.learning_rate = QLineEdit()
        self.learning_rate.setText("200")
        self.learning_rate.setToolTip("10.0から1000.0が推奨されています")
        learning_rate_h_box.addWidget(learning_rate_label)
        learning_rate_h_box.addStretch(1)
        learning_rate_h_box.addWidget(self.learning_rate)

        n_iter_h_box = QHBoxLayout()
        n_iter_label = QLabel("学習回数")
        self.n_iter = QLineEdit()
        self.n_iter.setText("1000")
        self.n_iter.setToolTip("250以上必要です")
        n_iter_h_box.addWidget(n_iter_label)
        n_iter_h_box.addStretch(1)
        n_iter_h_box.addWidget(self.n_iter)


        init_h_box = QHBoxLayout()
        init_label = QLabel("初期化")
        init_small_v_box=QHBoxLayout()
        random_h_box = QHBoxLayout()
        random_label = QLabel("ランダム")
        self.random = QRadioButton()
        self.random.toggle()
        random_h_box.addWidget(random_label)
        random_h_box.addWidget(self.random)
        pca_h_box=QHBoxLayout()
        pca_label = QLabel("PCA")
        self.pca = QRadioButton()
        pca_h_box.addWidget(pca_label)
        pca_h_box.addWidget(self.pca)
        self.button_group.addButton(self.random)
        self.button_group.addButton(self.pca)
        self.button_group = QButtonGroup()
        init_small_v_box.addLayout(random_h_box)
        init_small_v_box.addLayout(pca_h_box)
        init_h_box.addWidget(init_label)
        init_h_box.addStretch(1)
        init_h_box.addLayout(init_small_v_box)

        method_h_box = QHBoxLayout()
        method_label = QLabel("高速化")
        self.method_check_box = QCheckBox()
        self.method_check_box.setToolTip("チェックするとbarnes_hutアルゴリズムを用いて高速化します。<br>チェックなしで使用した方が正確な結果が出ます")
        self.method_check_box.toggle()
        method_h_box.addWidget(method_label)
        method_h_box.addStretch(1)
        method_h_box.addWidget(self.method_check_box)

        pre_reduction_h_box = QHBoxLayout()
        pre_reduction_label = QLabel("次元の削減")
        self.pre_reduction = QLineEdit()
        self.pre_reduction.setText("0")
        self.pre_reduction.setToolTip("あらかじめ次元数を削減することでノイズを除去します")
        pre_reduction_h_box.addWidget(pre_reduction_label)
        pre_reduction_h_box.addStretch(1)
        pre_reduction_h_box.addWidget(self.pre_reduction)

        variable_v_box.addStretch(1)
        variable_v_box.addLayout(perplexity_h_box)
        variable_v_box.addLayout(learning_rate_h_box)
        #variable_v_box.addLayout(init_h_box)
        variable_v_box.addLayout(n_iter_h_box)
        variable_v_box.addLayout(method_h_box)
        variable_v_box.addLayout(pre_reduction_h_box)
        variable_v_box.addStretch(1)


        push_button_v_box=QVBoxLayout()
        push_button_v_box.addLayout(to_from_a_box)

        for_analyze_v_box=QVBoxLayout()
        for_analyze_v_box.addLayout(word_a_box)

        button_h_box=QHBoxLayout()
        process_button=QPushButton("実行")
        process_button.clicked.connect(self.process)
        cancelB=QPushButton("閉じる")
        cancelB.clicked.connect(self.close_window)
        button_h_box.addStretch(2)
        button_h_box.addWidget(process_button)
        button_h_box.addWidget(cancelB)

        candidate_box.addLayout(radio_v_box)
        candidate_box.addStretch(1)
        candidate_box.addLayout(candidate_v_box)
        candidate_box.addLayout(push_button_v_box)
        candidate_box.addLayout(for_analyze_v_box)
        candidate_box.addLayout(variable_v_box)

        self.content_word.toggle()

        self.w.setGeometry(600, 300, 800, 450)
        self.w.setWindowTitle('2次元単語マップの作成(t-SNE)')

        main_layout = QVBoxLayout()
        main_layout.addLayout(candidate_box)
        main_layout.addLayout(button_h_box)
        self.w.setLayout(main_layout)

    def process(self):

        try:
            learn_rate = int(self.learning_rate.text())
            perplexity = int(self.perplexity.text())
            int(self.n_iter.text())
            int(self.pre_reduction.text())


            if len(self.word_a_items) == 0 :
                message=QMessageBox.information(self, "お知らせ","単語を追加してください", QMessageBox.Ok)
            #elif int(self.learning_rate.text()).isdigit() != True and int(self.perplexity.text()).isdigit != True and int(self.n_iter.text()).isdigit() != True and int(self.pre_reduction.text()).isdigit() != True:
            #    message=QMessageBox.information(self, "お知らせ","パラメーターには数字を入力してください", QMessageBox.Ok)
            else:
                reply = QMessageBox.question(self, '開始してもよろしいですか？',
                    "この処理は時間がかかります。<br>開始してもよろしいですか?", QMessageBox.No |
                    QMessageBox.Yes, QMessageBox.No)

                if reply == QMessageBox.Yes:
                    words=[]
                    for i in range(self.word_a_items.count()):
                        words.append(self.word_a_items.item(i).text())


                    if self.random.isChecked() == True:
                        init = "random"
                    else:
                        init = "pca"

                    if self.method_check_box.checkState() > 0:
                        method = "barnes_hut"
                    else:
                        method = "exact"

                    try:
                        Tsne(self.project, words, int(self.learning_rate.text()), int(self.perplexity.text()), init, int(self.n_iter.text()), method, int(self.pre_reduction.text()), self.model)
                    except Exception as e:
                        print(e)
                        message=QMessageBox.information(self,"お知らせ", "登録されていない単語を使用していませんか？<br>supervisedで学習した場合は、登録された単語しか使用できません", QMessageBox.Ok)
                else:
                    pass
            pass
        except Exception as e:
            print(e)
            message=QMessageBox.information(self, "お知らせ","パラメーターには半角数字を入力してください", QMessageBox.Ok)

    def input_word_a(self):
        if self.add_word_a.text() =="":
            pass
        else:
            add_word_a = self.add_word_a.text().replace("　", " ")
            add_word_a = add_word_a .split(" ")
            for n in add_word_a:
                self.word_a_items.addItem(n)
            self.add_word_a.clear()

    def to_word_a(self):
        if self.selected_word == "":
            pass
        else:
            for n in self.selected_word:
                self.word_a_items.addItem(n)
            for SelectedItem in self.candidate_word.selectedItems():
                self.candidate_word.takeItem(self.candidate_word.row(SelectedItem))

    def change_item(self):
        a=self.candidate_word.selectedItems()
        self.selected_word=[]
        for n in a:
            self.selected_word.append(n.text())

    def from_word_a(self):
        if self.selected_word_a == "":
            pass
        else:
            for n in self.selected_word_a:
                self.candidate_word.addItem(n)
            for SelectedItem in self.word_a_items.selectedItems():
                self.word_a_items.takeItem(self.word_a_items.row(SelectedItem))

    def change_item_a(self):
        a=self.word_a_items.selectedItems()
        self.selected_word_a=[]
        for n in a:
            self.selected_word_a.append(n.text())

    def search_word(self):
        cfg=configparser.ConfigParser()
        file_path = self.project + ".ini"
        cfg.read(file_path)
        data_type=cfg['project']["original_data_type"]

        if data_type == "1":
            message=QMessageBox.information(self, "お知らせ","この機能はご使用できません", QMessageBox.Ok)
        else:
            if self.content_word.isChecked() == True:
                content_word_check=0
            else:
                content_word_check=1
            minn=self.min.text()
            res = count(self.project, content_word_check, minn).word_list
            self.insert_candidate_word(res)

    def insert_candidate_word(self, words):
        for n in words:
            n=n[0]
            self.candidate_word.addItem(n)

    def close_window(self):
        self.w.close()

    #def closeEvent(self, event):
    #    self.model.items.clear()

    def show(self):
        self.w.exec_()

if __name__=="__main__":
    app=QApplication(sys.argv)
    project="syosetu"
    path = os.getcwd() + "/fastText/" + project + ".bin"
    model = FastText(path)
    #ex=open_project_SubWindow(pro).open_project()
    Tsne_graph_SubWindow(project, model).show()
    sys.exit(app.exec_())
