'''
    Random_Picker 用Python实现的随机点名器
    Copyright (C) 2022 海Cha

    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 xlrd as excel
from tkinter import *
import tkinter.messagebox as msgbox
import random
import sys
import winsound
import webbrowser

version = "v1.2.2"

filename = "./data/names.xls"
configname = "./data/config.data"
selname = "./assets/sel.wav"
procname = "./assets/proc.wav"
iconname = "./assets/点名器.ico"
gui_size = "650x200"

protection_override = False
up_percent = 30
down_persent = 40
elim_rows = 1
percent_override = True

elim_id = []
up_id = []
down_id = []

sound = True

students = []
classes = []
subjects = []
filter = []

last_choice = ""

gui = Tk()

gui.withdraw()
gui.title("点名器")
gui.geometry(gui_size)
gui.resizable(0,0)
gui.configure(bg = "white")

try:
    if len(sys.argv) > 1:
        for arg in sys.argv[1:]:
            if arg == "--licence":
                if msgbox.askokcancel('许可证信息', '点名器 ' + version + ' Copyright (C) 2022 海Cha\n本程序是开源程序，受开源协议 GNU General Public Licence v3.0 (GPL v3) 保护\n基于GPL v3协议，本程序没有任何质量保证。\n这是一个自由软件，欢迎再次分发。\n点击「确认」将会由系统默认浏览器打开LICENCE文件\n出现此对话框的原因是由于您在运行本软件时传入了 --licence 参数，欲启动主程序，请移除该参数。'):
                    webbrowser.open_new_tab('https://www.gnu.org/licenses/gpl-3.0.html')
                assert False
            if arg == "--version":
                msgbox.showinfo('版本信息', '点名器 ' + version + ' Copyright (C) 2022 海Cha\n出现此对话框的原因是由于您在运行本软件时传入了 --version 参数，欲启动主程序，请移除该参数。')
                assert False
            if arg == "--help":
                msgbox.showinfo('帮助信息','----- 点名器 ' + version + ' -----\n--licence 显示许可证信息\n--version 显示版本信息\n--path 显示程序运行路径\n--help 显示此信息\n欲打开主程序GUI，则无需传参\n出现此对话框的原因是由于您在运行本软件时传入了 --help 参数，欲启动主程序，请移除该参数。')
                assert False
            if arg == "--path":
                msgbox.showinfo('路径信息','点名器 ' + version + ' Copyright (C) 2022 海Cha\n当前程序运行在 ' + sys.argv[0] + ' 路径上\n出现此对话框的原因是由于您在运行本软件时传入了 --path 参数，欲启动主程序，请移除该参数。')
                assert False
            if arg.find("--") != -1:
                msgbox.showerror('传参错误','无法识别参数 ' + arg + ' 请调整您的启动参数\n传入 --help以查看帮助信息\n出现此对话框的原因是由于您在运行本软件时传入了 ' + arg + ' 参数，欲启动主程序，请移除该参数。')
                assert False
except AssertionError:
    sys.exit()

try:
    file = open(iconname)
    file.close()
    gui.iconbitmap(iconname)
except IOError:
    if not msgbox.askokcancel('资源文件错误', '在 ./assets目录下未能找到 点名器.ico 文件,点击「确定」将加载默认图标,点击「取消」以关闭程序'):
        sys.exit()

try:
    file = open(selname)
    file.close()
    file = open(procname)
    file.close()
except IOError:
    if msgbox.askokcancel('资源文件错误', '在 ./assets目录下未能找到音频文件,点击「确定」将关闭声音,点击「取消」以关闭程序'):
        sound = False
    else:
        sys.exit()

class Student(object):
    name = ""
    subject = ""
    id = ""
    class_name = ""

    def __init__(self,id,class_name,subject,name):
        self.id = id
        self.class_name = class_name
        self.subject = subject
        self.name = name

try:
    with excel.open_workbook(filename) as excel_data:
        table = excel_data.sheets()[0]
        # win32api.SetFileAttributes(filename,win32con.FILE_ATTRIBUTE_HIDDEN)
except FileNotFoundError:
    msgbox.showerror('找不到数据库文件', '在 ./data下未能找到 names.xls 文件,请确认您的文件存在')
    sys.exit()

try:
    cols = table.ncols
    rows = table.nrows
    assert cols == 4
    assert rows > 1
except AssertionError:
    msgbox.showerror('数据库文件格式不正确', '数据库文件内行/列数不合法,请确认数据库文件拥有超过1的行数和等于4的列数,当前行数:' + str(rows) + ' 当前列数:' + str(cols))
    sys.exit()

try:
   with open(configname,'r') as file:
        # win32api.SetFileAttributes(configname,win32con.FILE_ATTRIBUTE_HIDDEN)
        config = file.read().splitlines()
        for unit in config:
            temp = unit.split(",")
            if temp[1] == '0':
                elim_id.append(int(temp[0]))
            elif temp[1] == '+':
                up_id.append(int(temp[0]))
            elif temp[1] == "-":
                down_id.append(int(temp[0]))
            else:
                pass
except:
    percent_override = False

up_percent = len(up_id) * 5 if len(up_id) <= 6 else 30
down_percent = len(down_id) * 8 if len(down_id) <= 5 else 40

gui.deiconify()

for i in range(elim_rows,rows):
    tmp_list = [str(table.cell_value(i,j)) for j in range(0,cols)]
    if (int(float(tmp_list[0])) not in elim_id):
        student = Student(tmp_list[0],tmp_list[1],tmp_list[2],tmp_list[3])
        students.append(student)

cur_stu = students[:]

for student in students:
    if student.class_name not in classes:
        classes.append(student.class_name)
    if student.subject not in subjects:
        subjects.append(student.subject)

cur_name = StringVar()

def upd_name(name):
    cur_name.set(name)

upd_name("")

listbox = Listbox(gui, selectmode = MULTIPLE, height = 5)

for tmp_class in classes:
    listbox.insert("end",tmp_class)

def sel_class(flag = 1):
    global filter, listbox, classes, cur_stu, students, percent_override
    filter.clear()
    for selection in listbox.curselection():
        # print(selection)
        filter.append(classes[selection])
    # print(filter)
    if filter:
        if flag:
            msgbox.showinfo('班级选择已应用', '已应用当前班级选择', parent=gui)
            percent_override = False
        cur_stu.clear()
        for student in students:
            if student.class_name in filter:
                # print(student.name)
                cur_stu.append(student)
    else:
        if flag:
            msgbox.showwarning('班级选择已应用', '当前设置会选择所有班级的名单,这样对吗?', parent=gui)
            percent_override = False
        filter = classes[:]
        cur_stu = students[:]

def choose():
    global last_choice, cur_stu
    sel_class(0)
    # 触发30%概率,从up中挑选
    if (random.randint(1,100) < up_percent and percent_override):
        protection_override = True;
        temp = []
        for student in cur_stu:
            if int(float(student.id)) in up_id:
                temp.append(student)
        cur_stu = temp[:]
    elif (random.randint(1,100) < down_persent and percent_override):
        protection_override = True;
        temp = [];
        for student in cur_stu:
            if int(float(student.id)) not in down_id:
                temp.append(student)
        cur_stu = temp[:]
    else:
        protection_override = False
    if not cur_stu:
        protection_override = False
        sel_class(0)
    choice = random.choice(cur_stu)
    # print(choice.name)
    counter = 0;
    while (last_choice == choice.name and (not protection_override) and (len(cur_stu) > 1)) or choice.id in elim_id:
        choice = random.choice(cur_stu)
        counter = counter + 1
        if counter >= 100:
            break
        # print(choice.name)
    upd_name(choice.name)
    class_label.config(text = choice.class_name)
    subject_label.config(text = choice.subject)
    last_choice = choice.name
    if sound:
        winsound.PlaySound(selname, winsound.SND_ASYNC | winsound.SND_FILENAME)

startrandom = Button(gui, text = "立刻摇人!", font = ("宋体", 17, "bold"), height = 2, fg = "red", command = choose, bg = "white")
setclass = Button(gui, text = "应用班级选用", font = ("宋体", 17), height = 2, command = sel_class, bg = "white")
scrool = Scrollbar(gui, command = listbox.yview)
listbox.config(yscrollcommand=scrool.set)

name_label = Label(gui, textvariable = cur_name, font = ("宋体", 30, "bold"), width = 20, bg = "white", fg = "blue")
class_label = Label(gui, text = "", font = ("宋体", 15), width = 20, bg = "white")
subject_label = Label(gui, text = "", font = ("宋体", 15), width = 20, bg = "white")

class_label.grid(row = 2, column = 1, sticky = N+S+E+W)
subject_label.grid(row = 2, column = 2, sticky = N+S+E+W)
name_label.grid(row = 1, column = 1, sticky = N+S)
listbox.grid(row = 1, column = 2, sticky = N+S)
startrandom.grid(row = 3, column = 1, sticky = N+S+E+W)
setclass.grid(row = 3, column = 2, sticky = N+S+E+W)
scrool.grid(row = 1, column = 3, sticky = N+S)

gui.mainloop()