import pandas as pd
import math
import sys
def topsis():
    f = open("101903245-log.txt", "w")
    f.write("101903245.py started running : "+'\n')

    if len(sys.argv) > 5:
        f.write("less no. of arguments needed" + '\n')
        exit()
    elif len(sys.argv) < 5:
        f.write('all inputs not given' + '\n')
        exit()
    else:
        pass

    inputfile = sys.argv[1]


    try:
        # reading excel file
        data = pd.DataFrame(pd.read_excel(inputfile))
    except FileNotFoundError:
        f.write("Given File not found." + '\n')
        exit()

    # savind data as csv
    data.to_csv("101903245-data.csv")

    # storing shape of dataframe
    s=data.shape
    if s[1]<3:
        f.write("Input file must contain three or more columns" + '\n')
        exit()


    # handling null values
    # data.fillna(0)
    # data.fillna(method='ffill')
    # data.fillna(method='bfill')
    data.interpolate()

    #assigning weights
    # weights=[1]*(s[1]-1)
    weights=list(sys.argv[2])[::2]

    #assigning impacts
    # impacts=['+']*(s[1]-1)
    impacts=list(sys.argv[3])[::2]

    # Number of weights, number of impacts and number of columns (from 2nd to last columns) must be same.

    if len(weights)!=len(impacts) or len(impacts)!=(s[1]-1):
        f.write("Number of weights, number of impacts and number of columns (from 2nd to last columns) must be same." + '\n')
        exit()

    # impacts must be either +ve or -ve.
    for x in impacts:
        if x!="+" and x!="-":
            f.write("impacts must be either +ve or -ve." + '\n')
            exit()

    # Impacts and weights must be separated by ‘,’ (comma).
    wt=list(sys.argv[2])[1::2]
    it=list(sys.argv[3])[1::2]
    if it!=[","]*(len(impacts)-1) or wt!=[","]*(len(weights)-1):
        f.write("Impacts and weights must be separated by ‘,’ (comma)." + '\n')
        exit()


    #noramlized decision matrix including rss
    for y in range(1,s[1]):
        tmp=0
        for x in range(s[0]):
            tmp+=data.iloc[x,y]**2
        tmp=math.sqrt(tmp)
        for z in range(s[0]):
            data.iloc[z,y]=data.iloc[z,y]/tmp

    #weight assignment
    for y in range(1,s[1]):
        data.iloc[:,y]=data.iloc[:,y]*int(weights[y-1])

    #find ideal beat and ideal worst
    ibest=[0]*(s[1]-1)
    iworst=[0]*(s[1]-1)

    for y in range(1,s[1]):
        if impacts[y-1]=="+":
            ibest[y-1]=max(data.iloc[:,y])
            iworst[y-1]=min(data.iloc[:,y])
        elif impacts[y-1]=="-":
            ibest[y-1]=min(data.iloc[:,y])
            iworst[y-1]=max(data.iloc[:,y])

    #euclidean distance and pandn
    spos=[0]*s[0]
    sneg=[0]*s[0]
    pandn=[0]*s[0]

    for x in range(s[0]):
        ptmp=0
        ntmp=0
        for y in range(1,s[1]):
            ptmp+=(data.iloc[x,y]-ibest[y-1])**2
            ntmp+=(data.iloc[x,y]-iworst[y-1])**2
        spos[x]=ptmp
        sneg[x]=ntmp
        pandn[x]=ptmp+ntmp

    #performance score
    ps=[0]*s[0]

    for x in range(len(pandn)):
        ps[x]=sneg[x]/(spos[x]+sneg[x])

    #topsis score
    pscopy=sorted(ps,reverse=True)

    #ranking
    rank=[0]*s[0]

    for x in range(len(ps)):
        rank[x]=pscopy.index(ps[x])+1

    # addig score and rank to data
    data["Topsis Score"]=ps
    data["Rank"]=rank

    #rounding to 3decimal pts.
    data=round(data,3)

    #saving result as csv
    outputfile=sys.argv[4]
    # data.to_csv("101903245-result.csv")
    data.to_csv(outputfile)

    f.write("file executed successfully." + '\n')
    exit()

    # python topsis.py data.xlsx "1,1,1,2,1" "+,+,-,+,+" 101903245-output.csv
if __name__ == "__main__":
    topsis()