#Python 3 - Developed By Carter Fulcher
#Hello Developers! 

"""IMPORTANT NOTICE"""
#The dev code is 584. You will need this if you wish to use the
#interactive console. Thanks!


logo = """
  ______                         _          _____ _      _____     
 |  ____|                       | |        / ____| |    |_   _|    
 | |__ ___  _ __ _ __ ___  _   _| | __ _  | |    | |      | |      
 |  __/ _ \| '__| '_ ` _ \| | | | |/ _` | | |    | |      | |      
 | | | (_) | |  | | | | | | |_| | | (_| | | |____| |____ _| |_     
 |_|__\___/|_|  |_|_|_| |_|\__,_|_|\__,_|  \_____|______|_____|    
                                |_|                                                            
"""
import math
import sys
import readline # optional, will allow Up/Down/History in the console
import code
import functools #For the geomean function
import operator #For the geomean function
import os #for the clear function
instruction = """
Hi! Welcome to Formula CLI 2.0. FCLI2 is a command line based math tool. Truthfully, FCLI2 is the MOST versatile math tool out there. It is complete with over 50 built in formulas, with the easy ability for you to add more. In addition, you can create your own python functions that can be ran from the program. FCLI2 truly is the best tool for doing anything math related. 

  --Running a Formula--
  To run a formula just do "listformulas" to see a list of the avialable formulas; Next, just run the formula and enter in the desired value for the variables and FCLI2 will do the rest!
  --Running a Function--
  To run a function do "listfunctions" and this will show you all the avialable functions. Now, run "function" to let FCLI2 that you will be running a function and not a formula, then type the name of the desired function and you're off! 
  --Adding a Formula-- 
  If you want to add your own formula then simply look at the "forumals" dictionary. Here you can add formulas with a couple of easy steps. First, you need to specify the amount of variables that your formula will need in the first spot in the array, then enter the variables by name in the next couple spots. Finally, enter the formula AT THE LAST part of the array. Make sure the formula uses the same name you specified earlier
  --Adding a Function--
  This is easy. Just add your python function to the bottom of the program. Then, add the functions name to the "functions" list.
"""

formulas = { #Master Formula function! Add your formulas here!!!
  "trianglearea":["2", "b", "h", "0.5*(b*h)"],
  "squarearea":["2", "b", "h", "b*h"],
  "circlearea":["1", "r", "math.pi*(r)**2"],
  "findslope":["3", "y", "x", "b", "(y-b)/x"],
  "average2":["2", "n1", "n2", "(n1+n2)/2"],
  "geomean2":["2", "n1", "n2", "math.sqrt(n1*n2)"],
  "perimiterrect":["2", "l", "w", "(2*l)+(2*w)"],
  "volumerectprism":["3", "l", "w", "h", "l*w*h"],
  "pythagc":["2", "a", "b", "(a*a)+(b*b)"],
  "circum":["1", "r", "2*math.pi*r"],
  "cylvol":["2", "r", "h", "math.pi*(r*r)*h"],
  "spherevol":["1", "r", "(4/3)*math.pi*(r*r*r)"],
  "conevol":["2","r", "h", "(1/3)*math.pi*(r*r)*h"],
  "pyramidvol":["3", "l", "w", "h", "(l*w*h)/3"],
  "trapezoidarea":["3", "b1", "b2", "h", "((b1 + b2)/2)*h"],
  "exponentialgrowth":["4", "P", "r", "n", "t", "P * (1+r/n)**(n*t)"],
  "ngonarea":["3", "n", "a", "s", "n*(1/2)*a*s"],
  "sectorarea":["2", "measure_of_arc", "r", "(measure_of_arc/360)*math.pi*(r*r)"],
  "arclength":["2", "measure_of_arc", "r", "(measure_of_arc/360)*2*math.pi*r"],
  }


def init():
    print(logo)
    main()

#This function starts an interactive shell WITHIN the python script that allows you to access variables written here for testing.
def shell():
    #This forces users to have a code to enter. This is really insecure but that's ok! We are just trying to wee outpeople who are just using the program from messing with the developer console.
    devcode = 584 #THIS IS THE DEV COE
    print("Enter developer verification code (Or enter to go back):")
    devcode_verif = input()
    try:
        if devcode == int(devcode_verif):
            vars = globals().copy()
            vars.update(locals())
            shell = code.InteractiveConsole(vars)
            shell.interact()
        elif devcode != int(devcode_verif):
            print("Verification Failed.")
            main()
        elif devcode_verif == "":
            main()
    except ValueError:
        print("Verification Failed.")
        main()

#Main function. The init() function runs this to start the program. This function essentially recognizes commands and then deals with them accordingly. 
def main():  
    while True:
        runtime = input('Formula CLI 2.0 > ')
        
        commands = ["exit", "listformulas", "shell", "help", "commands", "asdf", "function", "listfunctions"]
        if runtime == commands[0]:
            sys.exit()
        if runtime == commands[1]:
            for key in formulas:
                print(key)
        if runtime == commands[2]:
            shell() #For Debugging, view shell() function for more information.
        if runtime == commands[3]:
            print(instruction)
        if runtime == commands[4]:
            print("Available commands:")
            for item in commands:
              print(item)
        if runtime == commands[5]:
          print("jklj;")
        if runtime == commands[6]:
          func = input('Enter Name of Function [name]: ')
          function(func)
        if runtime == commands[7]:
          for item in av_functions:
            print(item)
        elif runtime not in commands:
            print(compiler(runtime))

#Master Compiler Function
def compiler(formula):
  try:
    main = formulas[str(formula)] #Main Array that holds the formula
    variables = int(main[0]) #Number of Variables
    var = main[1:variables+1] #An array that contains str versions of the variables
    formula_master = main[-1]
    
  except KeyError:
    return "Formula not found."
  master_var = {}
  i = 0
  while i < variables:
    names = var[i]
    print("Enter Value of %s" % var[i])
    master_var[var[i]] = float(input())
    i+=1
  for key,val in master_var.items():
    exec(key + '=val')
    
  return(eval(formula_master))

def function(function_to_run):
  eval(function_to_run+"()")

av_functions = ["double", "calc", "geomean", "isprime"] #Enter functions here

"""Write functions below:"""

def double(): #A function that doubles a number. 
  i1 = input("number: ")
  print(int(i1)*2)

def calc(): #A simple calculator. Perform basic math functions here.
  print("Basic Calc Initializing...")
  print("Complete.")
  while True:
    master = input("> ")
    if(master == "exit"):
      main()
    else:
      print(eval(master))
      
def geomean(): #Calculate the geometric mean of unlimited numbers

    nums = input("Enter 2 or more numbers seperated by commas:  ")
    numbers = nums.split(",") #Splits by comma
    numbers = [ int(x) for x in numbers ] #String to integer

    new_numbers = functools.reduce(operator.mul, numbers, 1) 

    numlen = int(len(numbers)) #Number length

    print(int(new_numbers**(1/numlen))) #This is the square root to the nth

def isprime():
  num = int(input("Enter a number:  "))
  
  if(num % 2 == 0):
    print("The number is prime.")
  else:
    print("The number is not prime.")
  

  
#initialize the program by starting main()
init()
  
  

  
  
  
    
  
  
  
  
  
