#UTKARSH SANGWAN
#101903139
#3CO5

import pandas as pd;
import numpy as np;
import copy;
import math;
import sys;

def __main__():
    class Error_wrong_inputs(Exception):
        pass
    class Input_file_name(Exception):
        pass
    class Result_file_name(Exception):
        pass
    class weights_exception(Exception):
        pass
    class impacts_exception(Exception):
        pass
    class Col_Num_exception(Exception):
        pass
    class Not_Numeric_exception(Exception):
        pass
    class Postive_negative_exception(Exception):
        pass

    try:
        if len(sys.argv)<5 or len(sys.argv)>5:
            raise Error_wrong_inputs(len(sys.argv))
        file_name = sys.argv[1];
        df = pd.read_csv(file_name);
        if(len(df.columns)<3):
            raise Col_Num_exception(len(df.columns))
        for i in df.iloc[:-1,1:]:
            if not pd.to_numeric(df[i], errors='coerce').notnull().all():
                raise Not_Numeric_exception(i)
    except Error_wrong_inputs as err:
        print(f'Wrong number of inputs - {err}. Required 5')
    except FileNotFoundError:
        print(f'File with name {file_name} does not exist');
    except Col_Num_exception:
        print(f'The input file must contain 3 or more cols');
    except Not_Numeric_exception:
        print(f'All the values must be numeric');
    else:
        try:
            temp = file_name.split('.');
            weights =  sys.argv[2].split(",");
            impacts = sys.argv[3].split(",");
            result_file_name = sys.argv[4];
            temp2 = result_file_name.split('.');

            if not 'csv' in temp:
                raise Input_file_name(file_name)
            if not 'csv' in temp2:
                raise Result_file_name(result_file_name)
            if len(weights)!=len(df.columns)-1:
                raise weights_exception(weights)
            if len(impacts)!=len(df.columns)-1:
                raise impacts_exception(impacts)
            for i in impacts:
                if i != "+" and i!= "-":
                    raise Postive_negative_exception(i)
        except Input_file_name as err:
            print(f'Err:Input data file must be csv file')
        except Result_file_name as err:
            print(f'Err:Result data file name must be csv file')
        except weights_exception as err:
            print(f'Err: Weights should be equal to number of numeric cols and should be separated by commas')
        except impacts_exception as err:
            print(f'Err: Impacts should be equal to number of numeric cols and should be separated by commas')
        except Postive_negative_exception:
            print(f'All the values in impacts must be +ve or -ve');
        else:
            new_df = copy.copy(df);
            print(new_df);
            print(new_df.columns);
            #Normalization
            norm = []
            for i in new_df.iloc[:-1,1:]:
                sum=0
                for j in new_df.loc[:,i]:
                    j = float(j)
                    sum += j**2
                norm.append(math.sqrt(sum))
            print(f'Normalization Vector - {norm}')
            index=0
            for i in new_df.iloc[:-1,1:]:
                new_df[i] = new_df[i].div(norm[index])
                index = index+1
            print(f'Normalized Data Frame - {new_df}')

            index=0
            print(f'Weights are - {weights}')
            for i in new_df.iloc[:-1,1:]:
                new_df[i] = new_df[i] * float(weights[index])
                index = index+1

            print(f'Data Frame after assinging weights - {new_df}')

            index=0
            print(f'Impacts - {impacts}')
            ideal_best = []
            ideal_worst = []
            for i in new_df.iloc[:-1,1:]:
                if impacts[index]=='+':
                    ideal_best.append(new_df[i].max())
                    ideal_worst.append(new_df[i].min())
                else:
                    ideal_best.append(new_df[i].min())
                    ideal_worst.append(new_df[i].max())
                index = index+1

            print(f'Ideal Best - {ideal_best}')
            print(f'Ideal Worst - {ideal_worst}')

            EucBest = []
            EucWorst = []

            for i in range(0,len(new_df.iloc[:,:1])):
                best = 0
                worst = 0
                for index,j in enumerate(new_df.iloc[i,1:]):
                    best += (j-ideal_best[index])**2
                    worst += (j-ideal_worst[index])**2
                EucBest.append(math.sqrt(best))
                EucWorst.append(math.sqrt(worst))

            print(f'Euc Best - {EucBest}')
            print(f'Euc Worst - {EucWorst}')

            performance = []
            for i in range(0,len(EucBest)):
                performance.append(EucWorst[i]/(EucBest[i]+EucWorst[i]))

            print(f'Performance - {performance}')

            new_df['Topsis Score'] = performance

            new_df['Rank'] = new_df['Topsis Score'].rank(ascending=0)

            print(f'Data Frame with Topsis Score & rank - {new_df}')

            new_df.to_csv(result_file_name,index=False);