# 本ソースコードは、あくまで、Pythonの学習用・練習材料として提供するものです。
# 一通りデバグしてありますが、住所録としての動作を保証するものではありません。
# デバグが完璧ではなく、データの破損などが起こりえますが、瑕疵責任は負いません。
# 著作権は(有)りるらるが保持しますが、自由に改造・改良などでお使いください。
from adglobal import N, P, A, T, M, j  # global変数
import adclass
import adsub
import sys  # プログラムの強制停止関数:sys.exit()を使うために、importしておく。
import pdb  # デバグ開始関数:pdb.set_trace()を使うために、importしておく。
print("作業開始")  # プログラムの始まりを表示
# 住所録の存在するディレクトリは、global.pyの中で設定
adsub.setdir()  # 住所録の存在するディレクトリにカレントディレクトリを移す。
b = adclass.book("addressbook")  # addressbookという名前で住所録クラスを作る。
cnt1 = b.readab()
if cnt1 >= 0:  # 住所録ファイルが壊れているときはcnt1<0
    ct = [N[0], P[0], A[0], T[0], M[0]]  # 逐次入力、修正モードのコマンドのリスト
    na, pa, aa, ta, ma = [], [], [], [], []  # 項目毎のリスト
    ba = [na, pa, aa, ta, ma]  # 項目毎リストのリスト
    for p in b.a:  # 項目毎リストを作成
        adsub.eachappend(ba, p)
    ra = []
    b.show(ra)  # raが空のときは、住所録一覧表示
    ctf1 = True  # コマンド入力モードを継続させるためのフラグ(Trueのとき継続)
    cnf1 = True  # コマンド入力を省略させるためのフラグ(Trueのとき、コマンド入力する)
    ra = []  # 修正リスト、いきなり修正モードに行くとエラーになるのでここで初期化しておく。
    while ctf1:
        if cnf1:
            print("c:correct, d:dup-check, e:end, l:list, r:remove, ")  # コマンド一覧を表示
            print("s:sequential input, n,p,a,t,m:search")
            com = input("command:")
            if com == "":  # 何も入力しないで[Enter]すると住所録プログラムを終了
                ctf1 = False
                break
        c1 = com[0]
        match c1:
            case 'd':  # 二重データ確認(入力されたコマンド先頭文字が'd'のとき)
                t, u = [], []
                for i, p in enumerate(na):  # 重複の確認は名前に対して行う。
                    if p in t:
                        u.append(i)  # pがtの中に存在すれば、リストuに項目番号を付加
                    else:
                        t.append(p)  # pがtの中に存在しないときにはリストtに付加
                if len(u) > 0:  # リストuの中には、重複したデータの項目番号が入っている。
                    print("duplicate data exist.")
                    for i in u:
                        ra.append(i)  # 修正リストに入れる
                    b.show(ra)
                else:
                    print("no duplicate data")  # リストuが空のときは、重複データは存在しない。
            case "e":  # 終了コマンド
                ctf1 = False
                break
            case "r":  # 削除コマンド(先頭文字が'r'で続いて削除するデータの項目番号が来る)
                k = -1
                if com[1:].isdecimal():  # 項目番号が数字かどうか確認する。
                    k = int(com[1:])  # 文字列になっている項目番号を数値化
                if k >= 0 and k < len(b.a):  # 項目番号は、住所録データの範囲内にあるはず
                    b.a.pop(k)  # 住所録から削除
                    cnt1 -= 1  # データ個数を1減らす。
                else:
                    print("input error")
            case "l":  # 一覧表示コマンド(コマンド文字列の先頭が'l')
                ra = []
                b.show(ra)  # 一覧表示
            case "s":  # 逐次入力コマンド(コマンド文字列の先頭が's')
                ctf2 = True  # ctf2=Falseになると逐次入力モードを終了する
                rcnt = 0  # データ個数をクリア
                while ctf2:
                    d = {N: "", P: "", A: "", T: "", M: ""}  # 各項目データの初期値
                    for i, e in enumerate(j):  # eには、name, postcode, addressなどが入る。
                        data = input(e + ':')  # データを入力
                        data = adsub.zhconv(data)  # 郵便番号、電話番号が全角入力されてしまうことがあるので半角化する。
                        if data == "":  # 何も入れずに[Enter]すると逐次モードを抜ける。
                            ctf2 = False
                            break
                        if adsub.check_func[i](data):  # 各項目のデータが適正か確認(i:項目番号)
                            d[e] = data  # 辞書式にデータを保持
                        else:
                            print("illegal " + e)  # 入力データ・エラー
                            ctf2 = False
                            break
                    if d[N] == "":  # 全項目入力後、名前が入力されていない
                        ctf2 = False
                        break  # 逐次入力モードの終了
                    else:
                        s = adclass.person(list(d.values()))  # 辞書式に保持されたデータをリスト化して、personのインスタンスを作る。
                        b.a.append(s)  # 名前だけでも入力されていれば不完全でも登録する。
                        adsub.eachappend(ba, s)  # 項目毎リストにも登録する。
                        rcnt += 1
                        cnt1 += 1
                if rcnt == 0:  # 逐次入力終了時何も入力されていないときは、コマンド入力に戻る。
                    continue
                else:
                    k1 = len(b.a) - 1  # 末尾の項目番号(今入れたばかりのデータを指す)
                    ra2 = [k1]
                    s.show(ra2)  # 何か入力されている場合は、最終入力内容を表示して修正モードへ。len(b.a)-1は項目番号。
                    if d[N] != "" and d[M] == "":  # メールd[M]が入っているか?入っていれば修正モードに行かない。
                        ra = [k1]  # メールが入っていなければ修正リストに入れる
                        cnf1 = False  # 逐次入力が途中終了なら修正モードへ
                        com = "c" + str(k1)  # 逐次入力が途中終了ならcomに修正コマンドを作り修正モードへ
            case "c":  # 修正モード,ra[]に表示されている住所データの項目番号が入っている。
                if len(com) > 1:  # cコマンドでいきなり来る場合は、cに続いて修正する項目の番号が入っている。
                    k = -1
                    if com[1:].isdecimal():
                        no = int(com[1:])  # コマンド文字列から修正する項目の番号を取り出す。
                        if no >= 0 and no < len(b.a):  # 修正する項目番号をチェック
                            ra2 = [no]
                            b.show(ra2)  # 修正する項目内容を表示
                        else:
                            print("input error")
                            continue  # コマンド入力に戻る。
                    else:
                        print("input error")
                        continue  # コマンド入力に戻る。
                else:
                    if len(ra) > 1:  # raの内容は既に画面にデータが表示されている
                        com = input("which? enter no.:")  # 複数のデータから1つを選択する
                        if com.isdecimal():  # 入力された番号は数字か?
                            no = int(com)  # 入力された文字列を数値化
                            if no in ra:  # 指定された番号がraの中のものか確認
                                ra = [no]
                            else:
                                print("illegal input")
                                cnf1 = True
                                continue  # com[0]='c'のままなので、再度which?と表示される。
                        else:
                            print("illegal input")
                            cnf1 = True
                            continue  # com[0]='c'のままなので、再度which?と表示される。
                        if ra:
                            b.show(ra)  # 選ばれた番号を再度表示
                        else:
                            cnf1 = True
                            print("illegal no")
                            continue
                    else:
                        if ra:
                            no = ra[0]
                        else:
                            print("specify data no. following c")
                            continue
                d = b.a[no].fetch()  # 選択された番号のデータを辞書式に取り出す
                ctf2 = True
                while ctf2:  # ctf2=Trueである限り修正モードを継続
                    com = input("modify mode command(n,p,a,t,m,e):")
                    if com == "e" or com == "":  # 修正がイヤになった場合は何もせずに[Enter]する
                        ctf2 = False
                        break
                    if com[0] in ct:  # 入力されたコマンド文字列の先頭文字com[0]がコマンド
                        data = adsub.zhconv(com[1:])  # 2文字目以降com[1:]がデータ
                        i = ct.index(com[0])  # コマンド文字から項目番号を取得
                        if adsub.check_func[i](data):  # コマンドに引き続く文字列がデータ
                            d[j[i]] = data  # j[i]には、nameかpostcodeかaddressかtelnoかmailが入っている。これでは辞書式にする意味がない。
                        else:
                            print("illegal input")
                            continue
                    else:
                        print("command error")
                    b.a[no].fix(d)  # 住所録に修正を登録
                    ra2 = [no]
                    b.show(ra2)  # 修正内容を表示
                cnf1 = True  # コマンド入力へ
                ra = []  # 修正リストをクリア
            case _:  # queryコマンド、n, p, a, t, mに応じて関連データを探し出す
                ra = []  # 修正リストをクリア
                if com[0] in ct:  # com[0]がコマンドリストの中に一致するものがあるか?
                    i = ct.index(com[0])  # com[0]は何番目(どの項目)か?i:項目番号
                    for k, da in enumerate(ba[i]):  # 指定された番号の項目のリストからデータdaを取り出す。
                        if com[1:] in da:  # daの中に指定文字列com[1:]が含まれていれば選択する
                            ra.append(k)  # 修正項目リストに付加する。
                    if len(ra) > 0:
                        b.show(ra)  # 選択された項目のデータを表示する。
                        cnf1 = False  # コマンド入力には行かない。
                        com = "c"  # ra[]に項目番号を入れて、このまま修正モードへ
                else:
                    print("command error")  # コマンドとしてあり得ないものを入れると、コマンド入力に戻る。
                    cnf1 = True
                    continue
if cnt1 > 0:  # cnt1=0のときは書かない。データを全削除した場合でも元の住所録はそのまま。cnt1とするよりも、len(b.a)とすべきかも?
    b.writeab()
adsub.restoredir()  # カレントディレクトリを元に戻す。
print("作業終了")  # プログラムの終了を表示