#!/usr/bin/env python

"""
Gives general functionality of the curses application and definitions
"""

## IMPORTS ##
import curses
import curses.textpad as textpad
import os
import subprocess
import time
import datetime
from _thread import start_new_thread

#user created imports
import pystocker
from pystocker import *

## GLOBALS ##
x = 1
term_size_change = False
option_window_open = False

## FUNCTIONS ##
#initialize the curses window and return scr
def init_scr():
    
    scr = curses.initscr()

    curses.noecho()
    curses.cbreak()
    curses.curs_set(0)
    curses.halfdelay(20)
    scr.keypad(True)
    scr.clear()    

    return scr

#user scr to terminate the window and revert back to terminal
def term_scr(scr):

    curses.nocbreak()
    scr.keypad(False)
    curses.echo()
    curses.endwin()

#returns the number of columns or rows
def get_scr_dim(scr):
    return scr.getmaxyx()

#returns True if there has been a change in the window size, otherwise False
def check_term_size_change(scr, scr_dim):
    
    change = False

    if scr_dim != scr.getmaxyx():
        change = True

    return change

#opens a window that is 2/3 the size of the screen horizontally and vertically
def open_option_window(scr_dim):
    
    win = curses.newwin(int((int(scr_dim[0]) * 2 / 3)), int((int(scr_dim[1]) * 2 / 3)), int((int(scr_dim[0]) / 6) - 1), int((int(scr_dim[1]) / 6) - 1))

    return win

#creates the windows at the top, left and main segments
def open_top(scr_dim):
    
    top_scr = curses.newwin(4, scr_dim[1], 0, 0)

    return top_scr

def open_left(scr_dim):

    left_scr = curses.newwin(scr_dim[0]-5-1, 10, 5, 0)

    return left_scr

def open_main(scr_dim):

    main_scr = curses.newwin(scr_dim[0]-5-1, scr_dim[1]-10, 5, 10)

    return main_scr

def open_strip(scr_dim):

    strip_scr = curses.newwin(1, scr_dim[1], 4, 0)

    return strip_scr

def open_bottom(scr_dim):

    bottom_scr = curses.newwin(1, scr_dim[1], scr_dim[0]-1, 0)

    bottom_scr.addstr(0, 0, "[n]Add [d]Remove [h]Toggle Historical [s]Sort By [0/Esc]Exit")

    return bottom_scr

def window_colors(scr_top, scr_strip, scr_left, scr_main, scr_bottom):

    curses.start_color()

    curses.init_pair(1,curses.COLOR_WHITE,curses.COLOR_BLUE)
    curses.init_pair(2,curses.COLOR_WHITE,curses.COLOR_RED)
    curses.init_pair(3,curses.COLOR_WHITE,curses.COLOR_GREEN)
    curses.init_pair(4,curses.COLOR_WHITE,curses.COLOR_MAGENTA)

    #scr_top.bkgd(curses.color_pair(1))
    scr_strip.bkgd(curses.color_pair(1))
    #scr_left.bkgd(curses.color_pair(2))
    #scr_main.bkgd(curses.color_pair(3))
    scr_bottom.bkgd(curses.color_pair(4))

#refreshes the visible windows in order
def refresh_windows(scr_top, scr_strip, scr_left, scr_main, scr_bottom):

    scr_top.refresh()
    scr_strip.refresh()
    scr_left.refresh()
    scr_main.refresh()
    scr_bottom.refresh()

# open file to write the dictionary (may edit in future as JSON format)
def prepare_stock_dict(stock, data, stock_data_dict):
    
    stock_data_dict[str(stock)] = data

    return stock_data_dict

def write_stock_data(stock_data_dict):
    with open(root_path + "/.pystocker/stock_data", "w") as f:
        f.write(str(stock_data_dict))
    f.close()

def write_hist_data(hist_data_dict):
    with open(root_path + "/.pystocker/hist_data", "w") as f:
        f.write(str(hist_data_dict))
    f.close()

def get_data(arbN):
    os.chdir(root_path)

    x = 1

    historicals = 0

    stock_data_dict = {}
    hist_data_dict = {}

    row1 = {}
    row2 = {}
    row3 = {}

    perm_data_dict = [row1, row2, row3]

    while x == 1:
        stock_list = []
        stock_list = stocks.open_stock_codes()
        stock_data_dict.clear()

        for stock in stock_list:
            data = stocks.fetch_stock_data(stock[:-1])
            stock_data_dict = prepare_stock_dict(stock, data, stock_data_dict)

        write_stock_data(stock_data_dict)

        permanents_list = permanents.get_perm_list()
        
        counter = 0

        for row in permanents_list:
            for perm in row:
                perm_data = permanents.get_permanents(perm)
                perm_data_dict = permanents.prep_perm_dict(perm, perm_data, perm_data_dict, counter)
            counter = counter + 1

        permanents.write_perm_data(perm_data_dict)

        if historicals == 1:
            for stock in stock_list:
                if stock[:-1] not in hist_data_dict:
                    if stock not in hist_data_dict:
                        historicals = 0
            if historicals_get_datetime < datetime.datetime.now() - datetime.timedelta(minutes=30):
                historicals = 0

        if historicals == 0:
            hist_data_dict.clear()

            for stock in stock_list:
                hist_data = stocks.fetch_historical_data(stock[:-1])
                if hist_data != "Failed":
                    hist_data_dict = prepare_stock_dict(stock[:-1], hist_data, hist_data_dict)

            write_hist_data(hist_data_dict)
            
            historicals_get_datetime = datetime.datetime.now()
            historicals = 1
        time.sleep(10)


def set_up_environment(reset):

    root_path = os.path.expanduser("~")

    if not os.path.exists(root_path + "/.pystocker"):
        try:
            os.makedirs(root_path + "/.pystocker", exist_ok=True)
        except:
            os.makedirs(root_path + "/.pystocker")
    if not os.path.exists(root_path + "/.pystocker/permanents"):
        try:
            os.makedirs(root_path + "/.pystocker/permanents", exist_ok=True)
        except:
            os.makedirs(root_path + "/.pystocker/permanents")

    if not os.path.exists(root_path + "/.pystocker/info_settings"):
        file = open(root_path + "/.pystocker/info_settings", 'w')
        file.write("open\nprice\nchange\nvolume\naverage_daily_volume\nebitda\nmarket_cap\nbook_value\ndividend_per_share\ndividend_yield\nearnings_per_share\n52_week_high\n52_week_low\n50_day_moving_average\n200_day_moving_average\nprice_earnings_ratio\nprice_earnings_growth_ratio\nprice_sales_ratio\nprice_book_ratio\nshort_ratio")
        file.close
    if not os.path.exists(root_path + "/.pystocker/stock_codes"):
        open(root_path + "/.pystocker/stock_codes", "a").close()
    if not os.path.exists(root_path + "/.pystocker/stock_data"):
        open(root_path + "/.pystocker/stock_data", "a").close()
    if not os.path.exists(root_path + "/.pystocker/hist_data"):
        open(root_path + "/.pystocker/hist_data", "a").close()
    if not os.path.exists(root_path + "/.pystocker/permanents/perm_data"):
        open(root_path + "/.pystocker/permanents/perm_data", "a").close()
    if not os.path.exists(root_path + "/.pystocker/permanents/perm_l1"):
        file = open(root_path + "/.pystocker/permanents/perm_l1", "w")
        file.write("^NDX\n^GSPC\n^FTSE\n^AORD\n^HSI\n^N225")
        file.close()
    if not os.path.exists(root_path + "/.pystocker/permanents/perm_l2"):
        file = open(root_path + "/.pystocker/permanents/perm_l2", "w")
        file.write("GC=F\nSI=F\nHG=F\nCL=F")
        file.close()
    if not os.path.exists(root_path + "/.pystocker/permanents/perm_l3"):
        file = open(root_path + "/.pystocker/permanents/perm_l3", "w")
        file.write("USDAUD=X\nUSDEUR=X\nUSDJPY=X\nUSDCNY=X\nUSDGBP=X")
        file.close()

## WORKFLOW ##
scr = init_scr()
scr_dim = get_scr_dim(scr)

cursor = [0, 0, 0, 0]
stock_data_dict = {}
sort_order = [0, 0, 0]

move_up = False
top_point = False
lockCounter = 0
historicals = 0
historical_data = {}
date_list = []

root_path = os.path.expanduser("~")

set_up_environment(0)

start_new_thread(get_data, (0, ))

#main loop
while x != 48 and x != 27:
    term_size_change = check_term_size_change(scr, scr_dim)

    if term_size_change == True:
        term_scr(scr)
        scr = init_scr()
        scr_dim = get_scr_dim(scr)
        term_size_change == False

    scr_dim = get_scr_dim(scr)

    max_stock_range = scr_dim[0] - 6 - 1

    stock_list = stocks.open_stock_codes()
    if max_stock_range > len(stock_list):
        max_stock_range = len(stock_list)

    if x == 261:
        if historicals == 1:
            cursor = user_input.cursor_left(cursor)     # reverse for historicals
        else:
            cursor = user_input.cursor_right(cursor, historicals, scr_dim)
    elif x == 260:
        if historicals == 1:
            cursor = user_input.cursor_right(cursor, historicals, scr_dim)    #reverse for historicals
        else:
            cursor = user_input.cursor_left(cursor)
    elif x == 258:
        cursor = user_input.cursor_down(cursor, max_stock_range, move_up, scr_dim)
        if top_point == True:
            lockCounter = 0
        top_point = False    
        move_up = False
    elif x == 259:
        if cursor[2] == 1 and top_point == True:
            lockCounter = lockCounter - 1
        move_up = True
        cursor = user_input.cursor_up(cursor, max_stock_range)
        if cursor[2] == 1:
            top_point = True
    elif x == 100 or x == 263:
        if cursor[1] > 0 and cursor[1] <= total_stock_count:
            cursor[1] = cursor[1] - 1
            cursor[2] = cursor[2] - 1
            if move_up == True:
                delete_num = cursor[1] - (max_stock_range - cursor[2]) + (max_stock_range - cursor[1] + 1)
            else:
                delete_num = cursor[1]
            stock_data_dict = stocks.delete_stock_code(stock_list[delete_num], stock_data_dict)
    elif x == 110 or x == 78:
        cursor = user_input.input_n(cursor, scr_bottom, max_stock_range, stock_list, scr_dim)
        stock_list = stocks.open_stock_codes()
        move_up = False
        if max_stock_range > len(stock_list):
            max_stock_range = len(stock_list)
    elif x == 104:          #historical toggle
        if historicals == 0:
            historicals = 1
            cursor[0] = 0
            cursor[3] = -1
            historical_data = stocks.get_historical_data(stock_list)
        else:
            historicals = 0
            historical_data.clear()
            cursor[0] = 0
            cursor[3] = -1
            date_list = []
    elif x == 115:    #sort by
        if sort_order[0] == cursor[0] and cursor[3] == sort_order[1] and sort_order[2] == 1:
            sort_order[2] = 0
        elif sort_order[0] == cursor[0] and cursor[3] == sort_order[1] and sort_order[2] == 0:
            sort_order[2] = 1
        else:
            sort_order[2] = 0
        sort_order[0] = cursor[0]
        sort_order[1] = cursor[3]
        stock_list_sort = user_input.sort_stocks(cursor, stock_list, stock_data_dict, sort_order)

    shown_stocks = [0 + cursor[1] - cursor[2], max_stock_range + cursor[1] - cursor[2]]

    scr_top = open_top(scr_dim)
    scr_left = open_left(scr_dim)
    scr_main = open_main(scr_dim)
    scr_strip = open_strip(scr_dim)
    scr_bottom = open_bottom(scr_dim)

    window_colors(scr_top, scr_strip, scr_left, scr_main, scr_bottom)

    stock_list = stocks.open_stock_codes()
    
    total_stock_count = len(stock_list)
    
    stock_data_dict = stocks.get_all_data(stock_data_dict)

    counter = 0
    nCounter = counter

    stock_data = {}

    try:
        stock_list = stock_list_sort
    except:
        pass

    for stock in stock_list:
        if nCounter < cursor[1] - cursor[2] and move_up == False:
            nCounter = nCounter + 1
            lockCounter = nCounter
            continue

        if move_up == True and nCounter < lockCounter:
            nCounter = nCounter + 1
            continue

        if counter > max_stock_range - 1:
            continue
        if stock in stock_data_dict:
            data = stock_data_dict[str(stock)]
            stock_data[str(stock)] = stocks.Stock(str(stock), data)
            if historicals == 1:
                if stock[:-1] in historical_data.keys() or stock in historical_data.keys():
                    date_list = stocks.print_historicals(counter, historical_data[str(stock)[:-1]], scr_left, scr_main, scr_strip, x, cursor, scr_dim, stock_list, str(stock), date_list)
                else:
                    if cursor[2] == counter + 1:
                        scr_left.addstr(counter, 0, str(stock), curses.A_REVERSE)
                    else:
                        scr_left.addstr(counter, 0, str(stock), curses.A_BLINK)
            else:
                stocks.print_data(counter, stock_data[str(stock)], scr_left, scr_main, scr_strip, x, cursor, scr_dim)
            counter = counter + 1
        else:
            code_length_missing = 10 - len(stock)
            for space in range(code_length_missing):
                stock = stock + " "
            if cursor[2] == counter + 1:
                scr_left.addstr(counter, 0, str(stock), curses.A_REVERSE)
            else:
                scr_left.addstr(counter, 0, str(stock), curses.A_BLINK)
            counter = counter + 1

    perm_list = permanents.get_perm_list()

    perm_data_dict = permanents.read_perm_data()

    perm_counter = 0

    for row in perm_data_dict:
        perm_length = 0
        for perm in perm_list[perm_counter]:
            if perm in row:
                perm_length = perm_length + permanents.print_permanents(scr_top, perm, perm_counter, perm_length, row[perm], scr_dim)
        perm_counter = perm_counter + 1

    refresh_windows(scr_top, scr_strip, scr_left, scr_main, scr_bottom)

    curses.start_color()

    curses.init_pair(6, curses.COLOR_MAGENTA, curses.COLOR_BLACK)

    if cursor[3] == -1:
        if sort_order[2] == 0:
            scr_strip.addstr(0, 0, "v")
        else:
            scr_strip.addstr(0, 0, "^")
    else:
        if sort_order[2] == 0:
            scr_strip.addstr(0, 8, "v")
        else:
            scr_strip.addstr(0, 8, "^")
    scr_top.addstr(0, 0, "pystocker v0.1.25 - by coffeeandscripts", curses.color_pair(6))
    
    scr_strip.refresh()

    scr_top.refresh()

    x = scr.getch()

#terminating the window
#proc1.kill()                #must kill the process that runs get_data.py
term_scr(scr)               #terminate the ncurses screen function
