# Importe
import os.path
import sys
import time

def run():
  """
  None -> None
  Führt das Programm aus.
  """
  args = sys.argv # Die Liste aller Parameter des Programmaufrufs: {main.py, <1>, <2>, <3>, ..., <n>}
  path = ""
  if len(args)==2: # Prüft ob genau ein Parameter beim Programmaufruf übergeben wurde.
    path = args[1]
  else:
    path = eingabe_abfrage1()
  while not(os.path.isfile(path)) and path != "": # Prüft, ob der Pfad gültig ist.
    path = eingabe_abfrage1() # Fragt nach Eingabedateipfad
  if path != "": # Path ist nicht das zugelassene leere Wort.

    infile = read_file(path) # Datei wird als Liste aller Zeilen eingelesen 
    result_list = process_file(infile) # Datei wird in diverse Dictionarys verarbeitet und die Gesammttokenanzahl wird gezählt.

    length_words_dict = result_list[0]  # Dict für Aufgabe 1        {Tokenlänge:Menge aller Tokens dieser Länge}
    freq_words_dict = result_list[1]    # Dict für Aufgabe 2        {Häufigkeit:Liste der Wörter mit dieser Häufigkeit}
    words_freq_dict = result_list[2]    # Dict für Aufgabe 3 und 5  {Wort:Häufigkeit dieses Wortes}
    length_count_dict = result_list[3]  # Dict für Aufgabe 4        {Tokenlänge:Anzahl der Tokens dieser Länge}
    token_count = result_list[4]        # Int für Aufgabe 4         die Anzahl aller Tokens der gegebenen Datei
    rank_words_dict = result_list[5]    # Dict für Aufgabe 5        {Rang:Liste der Worte dieses Ranges}

    # Eingabeaufforderung für die Auswahl der Operation
    input2 = eingabe_abfrage2()
    print()

    while input2!="": # Solange der input nicht das leere Wort ist.

      if input2 == "1": 
        max_words = len(words_freq_dict)
        aufgabe1(length_words_dict, max_words) # Aufgabenteil 1

      elif input2 == "2": 
        aufgabe2(freq_words_dict) # Aufgabenteil 2

      elif input2 == "3": 
        aufgabe3(words_freq_dict) # Aufgabenteil 3

      elif input2 == "4": 
        aufgabe4(length_count_dict, token_count) # Aufgabenteil 4

      elif input2 == "5":
        aufgabe5(words_freq_dict, rank_words_dict, len(length_words_dict.keys())) # Aufgabenteil 5

      time.sleep(1) # Wartet n Sekund(en), bis das Programm weiter ausgeführt wird.
      input2 = eingabe_abfrage2()
      print("")

def eingabe_abfrage1():
  """
  None -> String
  Fragt nach einer Eingabe und gibt sie als String zurück.
  """
  print("Geben Sie eine gültige Token-Datei ein.(Enter zum Beenden)")
  return input(">>>")

def eingabe_abfrage2():
  """
  None -> String
  Fragt nach einer Eingabe und gibt sie als String zurück.
  """
  print("")
  print("Geben Sie 1 ein, um die [n] längsten/kürzesten Wörter zu ermitteln.")
  print("Geben Sie 2 ein, um die [n] häufigsten/seltensten Wörter zu ermitteln.")
  print("Geben Sie 3 ein, um den Anteil eines [Tokens] am Gesamttext zu ermitteln.")
  print("Geben Sie 4 ein, um den Anteil der Worttoken mit Mindest-/Höchstlänge [m][n] am Gesamttext zu ermitteln.")
  print("Geben Sie 5 ein, um den Text auf das Zipfsche Gesetzt zu prüfen.")
  print("(Enter zum Beenden)")
  return input(">>>")


def read_file(path):
  """
  string -> list
  Erzeugt aus einer Datei mit gegebenem Pfad path eine Liste der Zeilen.
  """
  infile = open(path, mode="r", encoding="utf8" )
  data = infile.readlines()
  infile.close()
  return data

def process_file(file_data):
  """
  list -> list() = {dictionary1,dictionary2,dictionary3,dictionary4,int}
  Erzeugt aus der Datei des gegebenen Dateipfads
  eine Liste mit 2 Elementen:
  einem Dictionary mit {Tokenlänge:Menge aller Tokens dieser Länge},        <-- für A1
  einem Dictionary mit {Häufigkeit:Liste der Wörter mit dieser Häufigkeit}, <-- für A2
  einem Dictionary mit {Wort:Häufigkeit},                                   <-- für A3 und A5
  einem Dictionary mit {Tokenlänge:Anzahl der Tokens dieser Länge},         <-- für A4
  einer Zahl - die Anzahl aller Tokens der gegebenen Datei                  <-- für A4
  einem Dictionary mit {Rang:Liste der Wörter mit diesem Rang},             <-- für A5
  """
  length_words_dict = dict() # Dict für Aufgabe 1
  freq_words_dict = dict() # Dict für Aufgabe 2
  rank_words_dict = dict() # Dict für Aufgabe 5
  words_freq_dict = dict() # Dict für Aufgabe 3 und 5
  length_count_dict = dict() # Dict für Aufgabe 4
  token_count = 0 # Int für Aufgabe 4
  for token in file_data:
    token = token.strip("\n.,!?.;'\"\\/´`^(){}[]1234567890\"").upper() # Entfernt Sonderzeichen und vereinheitlicht Tokens
    length = len(token)
    
    if length > 0 and token != "": # Prüft ob die eingelesene Zeile noch einen verarbeitbaren Token enthält
      token_count = token_count + 1 # Zählt Token
      # Dict 1 {Tokenlänge:Menge aller Tokens dieser Länge} 
      # Dict 4 {Tokenlänge:Anzahl der Tokens dieser Länge}
      if not(length in length_count_dict): # Wenn ein Länge noch nicht im Dictionary 1 oder 4 vorhanden ist.
        wordset = set()
        wordset.add(token) # Token wird in eine Menge eingetragen
        length_words_dict.update({length:wordset}) # Füllt Dict1 mit der Menge die den Token enthält
        length_count_dict.update({length:1}) # Füllt Dict4 und setzt die Tokenanzahl dieser Tokenlänge auf 1
      else:
        length_words_dict[len(token)].add(token) # Füllt die Menge Dict1 mit dem noch nicht enthaltenen Token
        length_count_dict.update({length:(length_count_dict[length]+1)}) # In Dict 4 wird der Zähler der Tokenlänge um 1 erhöht 

      # Dict 3 {Wort:Häufigkeit}
      if token not in words_freq_dict:        
        words_freq_dict.update({token:1}) # Setzt Häufigkeit des Tokens auf 1
      else:
        words_freq_dict[token] += 1 # Erhöht die Häufigkeit des Tokens um 1

  # Dict 2 {Häufigkeit: Liste der Wörter mit dieser Häufigkeit}
  for elem in words_freq_dict:
    key = words_freq_dict[elem] # Tauscht Value mit Key
    value = [elem]              # und legt den Key in eine Liste als Value -> Dreht das Wort:Häufigkeits Dictionary  
    if key in freq_words_dict:
      freq_words_dict[key] = freq_words_dict[key] + [elem] # Ergänzt Wort der Liste Häufigkeit
    else:
      freq_words_dict[key] = value

  # Dict 5 {Rang: Liste der Wörter mit diesem Rang}
  freq_list = list(freq_words_dict.keys()) # Erstellt eine Liste aller vorkommenden Häufigkeiten (aufsteigend sortiert)
  freq_list = freq_list[::-1] # Dreht die Liste in absteigende Sortierung
  rank = 1
  for freq in freq_list:
    rank_words_dict[rank] = freq_words_dict[freq]
    rank += len(freq_words_dict[freq]) # Erhöht den Rang um die Menge der Wörter die den aktuellen Rang haben.

  # Ergebnis Liste
  result_list = list()
  result_list.append(length_words_dict)
  result_list.append(freq_words_dict)
  result_list.append(words_freq_dict)
  result_list.append(length_count_dict)  
  result_list.append(token_count)
  result_list.append(rank_words_dict)

  return result_list
   
def aufgabe1(input_dict,max_words):
  """
  String -> None
  Führt Aufgabenstellung 1 mit Sonias Programm aus.
  """
  length_words = input_dict
  n = (input("Die wie viel kürzesten und längsten Wörter sollen ausgegeben werden? "))
  while not n.isdigit():
    n = (input("Die wie viel kürzesten und längsten Wörter sollen ausgegeben werden? "))
  max_wort(int(n),length_words,max_words)
  min_wort(int(n),length_words,max_words)

def max_wort(n,length_words,max_worte):#=length_words):
  if max_worte > 0:
          #n=int(input("Die wie viel längsten Wörter sollen ausgegeben werden?"))
          i=1
 
          #global length_words

          max_buchstabenanzahl= max(length_words.keys())
          longest_words= length_words [max(length_words.keys())]
          anzahl_worte = len(longest_words)
         

          print ("Die Wörter/das Wort:" ,longest_words,"haben/hat", max_buchstabenanzahl, "Buchstaben!") 
          
          
          
          while anzahl_worte <n and anzahl_worte<max_worte:
              
               max_buchstabenanzahl_i = max_buchstabenanzahl -i
               if max_buchstabenanzahl_i in length_words.keys():
                    
                    longest_words_i=length_words [max_buchstabenanzahl_i]
                    print ("Die Wörter:" ,length_words [max_buchstabenanzahl_i] ,"haben" ,max_buchstabenanzahl_i ,"Buchstaben!")
                    anzahl_worte =anzahl_worte + len(longest_words_i)

               i=i+1




#n=int(input("Die wie viel längsten Wörter sollen ausgegeben werden?"))
#max_wort(n)

def min_wort(n,length_words,max_worte):#=length_words):
  if max_worte > 0:
          #n=int(input("Die wie viel kürzesten Wörter sollen ausgegeben werden?"))
          i=1
 
          #global length_words

          min_buchstabenanzahl= min(length_words.keys())
          shortest_words= length_words [min(length_words.keys())]
          anzahl_worte = len(shortest_words)
         

          print ("Die Wörter/das Wort:" ,shortest_words,"haben/hat", min_buchstabenanzahl, "Buchstaben!") 
          
          
          
          while anzahl_worte <n and anzahl_worte<max_worte:
              
               min_buchstabenanzahl_i = min_buchstabenanzahl +i
               if min_buchstabenanzahl_i in length_words.keys():
                    
                    shortest_words_i=length_words [min_buchstabenanzahl_i]
                    print ("Die Wörter:" ,length_words [min_buchstabenanzahl_i] ,"haben" ,min_buchstabenanzahl_i ,"Buchstaben!")
                    anzahl_worte =anzahl_worte + len(shortest_words_i)

               i=i+1


def aufgabe2(input_dict):
  """
  String -> None
  Führt Aufgabenstellung 2 mit Kims Programm aus.
  """
  lex2 = input_dict # Erstellt ein Dictionary
  n = (input("Die n häufigsten und seltensten Wörter: n = "))
  while not n.isdigit():
    n = (input("Die n häufigsten und seltensten Wörter: n = "))
  freq_words(int(n),lex2)

##################
#Funktion für die n häufigsten und seltensten
def freq_words(n, lex2):

	liste = list(lex2.keys())
	i = 0
	j = 0

	if n > len(liste):
		n = len(liste)
	
	#hÃ€ufigsten
	liste = liste[::-1]
	print("Most frequent:")
	while(i<n):
		print("Mit einer HÃ€ufigkeit von", liste[i])
		print(lex2[liste[i]])
		i=i+1

	print("----------------------------------------")

	#seltensten
	liste = liste[::-1]
	print("Least frequent:")
	while(j<n):
		print ("Mit einer HÃ€ufigkeit von", liste[j])
		print(lex2[liste[j]])
		j=j+1


def aufgabe3(input_dict):
  """
  String -> None
  Führt Aufgabenstellung 3 mit Annas Programm aus.
  """
  type_s = input_dict # Erstellt ein Dictionary
  wort = input("Wort dessen Share berechnet werden soll: ").upper()
  wort_anteil = share_type(type_s,wort)
  if wort_anteil != None:
    print(wort_anteil,"%")
  else:
    print("Dieses Wort ist im Text nicht enthalten.")

def share_type(type_s,wort): 

    #type_s ist ein dictionary mit {typ:anzahl}
    #type_s = types.types()
    #wort = input("Wort dessen Share berechnet werden soll: ").upper()
    
    if wort in type_s:
        einzelwert = type_s[wort]
        gesamtwert = 0
        
        for key in type_s:
            gesamtwert = gesamtwert + type_s[key]
            
        wort_anteil = round((einzelwert/gesamtwert*100),3) # Wird auf 3 Nachkommastellen gerundet
        return wort_anteil
          
    elif wort not in type_s: 
        return None

def aufgabe4(input_dict,token_count):
  """
  String -> None
  Führt Aufgabenstellung 4 mit Pascals Programm aus.
  """
  length_count_dict = input_dict # pascal.make_dict(path) # Erstellt ein Dictionary
  print("Geben Sie an, aus welchem Wortlängen-Interval(m,n) Sie den Anteil berechnen möchten: ")
  m = (input("Untere Schranke n: "))
  while not m.isdigit():
    m = (input("Gültige untere Schranke n: "))
  n = (input("Obere Schranke n: "))
  while not n.isdigit():
    n = (input("Gültige obere Schranke n: "))
  result = str(length_perc(int(m),int(n),length_count_dict,token_count))
  print(result+"%")

def length_perc(m,n,token_length_dict,token_count):
  """
  Int, Int -> Float
  Erzeugt aus den übergebenen Integerwerten den Prozentsatz, den Wörter der Länge n bis einschließlich m
  im vorgelegten Text ausmachen.
  """
  if token_count > 0:
    if n < m:
      t = m
      m = n
      n = t
    keys = list(token_length_dict.keys())
    sorted(keys)
    keys = keys[::-1]
    token_count_length = keys[0]
    if m <= 0:
      m = 1
    if n >= token_count_length:
      n = token_count_length
    result = 0
    for i in range(m,n+1):
      if i in token_length_dict:
        result = result + token_length_dict[i]
    return round((result/token_count)*100,3)
  else:
    return 0

def aufgabe5(input_dict1,input_dict2,max_length):
  """
  String -> None
  Führt Aufgabenstellung 5 mit Christines Programm aus.
  """
  words_freq_dict = input_dict1
  rank_words_dict = input_dict2
  result = zipf(words_freq_dict, rank_words_dict)
  whitespace = " "
  gap = 2
  gap1= max(gap + len(str(len(result))),6)
  gap2= max(gap + max_length,6)
  print("Rang: %s Wort: %s Zipfsche Konstante: " % (whitespace * int(gap1-5) , whitespace * int(gap2-5)))
  for key in sorted(result):
    tmp_gap1 = gap1-len(str(key[0]))
    tmp_gap2 = gap2-len(key[1])
    print("%s %s %s %s %s" % (key[0],whitespace*tmp_gap1, key[1],whitespace*tmp_gap2 , result[key][0]))

def zipf(dict1,dict2):
    """
    (dict, dict) -> None
    Berechnet aus den dictionnarys words_freq_dict und rank_words_dict die Zipfsche Konstante
    """
    dict_zipf = dict()
    gesamtwert = 0
    for key in dict1:
        gesamtwert = gesamtwert + dict1[key]
    for wort, anzahl in dict1.items():
        for rang, liste in dict2.items():
            if wort in liste:
                zipf = (anzahl/gesamtwert)*rang*100
                dict_zipf[rang, wort]= [zipf]
    return dict_zipf

run()
