#!/usr/bin/env python
# coding: Shift_JIS

# ##############################

# ファイル名: exception_handling.py
# 機能: ユーザが選択した状態変数を含む制御構文のネストの深さや，状態変数の取りうる値の種類が既定の値よりも大きい場合，警告・エラー文を生成する．
# 関数: ReportException, getCondVal, getCondDepth, exception_handling
# 著者名: 山本椋太，若林丈紘

# ##############################

import os
import re
import sys

DEPTH_MAX = 5
VALS_MAXNUM = 20

# ##############################

# 関数名: ReportException
# 機能: エラー内容をTSV_info/stm_report_message.txtに書き出す．
# 引数
#   error_message: エラー内容

# ##############################

def ReportException(report_message):
    reportfile= "TSV_info/stm_report_message.txt"

    if os.path.exists("TSV_info/stm_report_message.txt"):
        message = open(reportfile,"a")
    else:
        message = open(reportfile,"w")
    message.write(report_message)
    message.close()

# ##############################

# 関数名: getCondVal
# 機能: 条件式中で状態変数が比較されている値を調べる．
# 引数
#   instring: 解析中の行
#   param: 状態変数

# ##############################

# INPUT: id_linesの各行，状態変数名
# OUTPUT: ある条件式で状態変数が比較されている値
def getCondVal(instring,param):
    if re.match(".*if\("+ param +"\s*==",instring):
        row = instring.split("==")
        val = row[1].rsplit(")")[0]
        if re.match("\(.+\)",val):
            val = val[1:-1]
        else:
            val = val
    else:
        val = ""
    return val

# ##############################

# 関数名: getCondVal
# 機能: 状態変数を含む条件式のネストの深さを調べる．
# 引数
#   instring: 解析中の行
#   param: 状態変数

# ##############################

# INPUT: id_linesの各行，状態変数名
# OUTPUT: 状態変数を含む条件式のネストの深さ
#         (状態変数が存在しない場合は0を返す）
def getCondDepth(instring,param):
    if re.match(".*if\("+param, instring):
        nest_depth = instring.rsplit("\t")[-1].replace("\n","")
    else:
        nest_depth = 0

    return int(nest_depth)

# ##############################

# 関数名: exception_handling
# 機能: id_listの各行を参照し，想定しないパターンに対して警告・エラーを出力する．
# 引数
#   param: 除隊変数
#   directory: 解析対象の関数に関する情報がまとめられたディレクトリ

# ##############################

def exception_handling(param,directory):


    print("\n===============")
    print("= exception_handling =")
    print("param: ", param)
    print("directory: ",directory)
    print("===============\n")

    # ############################

    # 関数: exception_handling
    # 機能： 1) id_listの各行を参照し，想定しないパターンに対して警告・エラーを出力する

    # INPUT ： idlist2-5.tsv
    # OUTPUT: stm_report_message.tsv

    # INPUTの入力元 : temp/FUNCTION/ (FUNCTIONは任意の関数名)
    # OUTPUTの出力先: TSV_info/

    # idlist2-5.tsv   : 各関数における条件式の一覧

    # stm_report_message.tsv : 各関数における警告・エラー文をまとめたファイル
    #                          各行のフォーマットは "WARNING:[(関数名)] (警告内容)\n" ，
    #                                      あるいは  "ERROR:[(関数名)] (エラー内容)\n"
    # ############################

    out_directory = "temp/" + directory + "/"

    rfile = out_directory + "idlist2_5.tsv"
    fi = open(rfile)
    lines = fi.readlines()
    fi.close()

    funcname = ""
    allMJKflg = True
    compare_operators = ["<",">","&&","||","!="]

    for i,line in enumerate(lines):
        depth = line.rsplit("\t")[-1].replace("\n","")
        code = line.split("\t")[1]
        nest = int(line.split("\t")[2])

        if int(depth) == 0:
            tmp = line.split("\t")[0]
            funcname = line.split("\t")[1]
            depth = 0
            vals = []
            val_cands = []
            overdepth_flg = False
            overvalnum_flg = False
            unknownope_flg = False
            allMJKflg = True
            jotaisenni = False


        if("if(" in code):
            cond = code.split("(",1)[1].rsplit(")",1)[0]
            if "==" in cond:
                cond_l = cond.split("==")[0].replace(" ","")
                cond_r = cond.split("==")[1].replace(" ","")
                if param == cond_l or param == cond_r:
                    print(cond_l,cond_r)
                    jotaisenni = True
            else:
                cond = cond.replace(" ","")
                if param == cond:
                    jotaisenni = True

        if("if(" in code and param in code):
            cond = code.split("(",1)[1].rsplit(")",1)[0]
            val_cands.append(cond.replace(" ","").split("==")[0])
            for cope in compare_operators:
                if cope in cond:
                   print("ERROR: A comparison operator that is not [==] is used.\n[" + funcname + "]")
                   ReportException("ERROR:[" + funcname + "] [==]以外の比較演算子が使われています。\n")
                   return False
                   unknownope_flg = True


        cond_depth = getCondDepth(line,param)
        nest_outside = cond_depth - 1
        if nest_outside > DEPTH_MAX and overdepth_flg == False:
            print("ERROR: The depth of the nest outside the control syntax containing the state variable exceeds the specified number.\n[" + funcname + "]")
            ReportException("ERROR:[" + funcname + "] 状態変数を含む制御構文の外側にあるネストの深さが規定の数を超えています。\n")
            return False
            overdepth_flg = True


        val = getCondVal(line,param)
        if val != "" and not(val in vals):
            vals.append(val)

        if len(vals) >= VALS_MAXNUM and overvalnum_flg == False:
            print("ERROR: The number of constant values taken by the state variable exceeds the limit.\n[" + funcname + "]")
            ReportException("ERROR:[" + funcname + "] 状態変数の取りうる定数値の種類が規定の数を超えています。\n")
            return False
            overvalnum_flg = True



        if nest == 1:
            if "%%%MJK%%%" not in line:
                allMJKflg = False

        if len(lines)-1 != i:
            if lines[i+1][-1] == "0" and allMJKflg == True:
               print("WARNING: Event does not exist.\n[" + funcname + "]")
               ReportException("WARNING:[" + funcname + "] イベントが存在しません。\n")

        if len(lines)-1 == i and allMJKflg == True:
               print("WARNING: Event does not exist.\n[" + funcname + "]")
               ReportException("WARNING:[" + funcname + "] イベントが存在しません。\n")

        if len(lines)-1 == i and jotaisenni == False:
               print("WARNING: State transition does not exist.\n[" + funcname + "]")
               ReportException("WARNING:[" + funcname + "] 状態変数を含む条件式が存在しません。\n")

        if len(lines)-1 == i and (param not in val_cands or len(val_cands)==0):
               print("WARNING: State variable does not exist.\n[" + funcname + "]")
               ReportException("WARNING:[" + funcname + "] 状態変数が存在しません。\n")

if __name__ == '__main__' :
    exception_handling(sys.argv[1],sys.argv[2])
