#!/usr/bin/python 
# -*- coding: utf-8 -*- 

# Quickcal - fast and easy to use calculator with support for filing
# Copyright (C) 2017 Nathan SR <cquickcal@gmail.com> 

# License: 

#    quickcal is free software: you can redistribute it and/or modify 
#    it under the terms of the GNU General Public License as published by 
#    the Free Software Foundation, either version 3 of the License, or 
#    (at your option) any later version. 
# 
#    quickcal is distributed in the hope that it will be useful, 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
#    GNU General Public License for more details. 
# 
#    You should have received a copy of the GNU General Public License 
#    along with quickcal.  If not, see <http://www.gnu.org/licenses/>. 

# Necessary Imports

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk 
from gi.repository import Pango
import subprocess
import re
import os, errno
import datetime
import time
import sys

# Following checks for specific characters in inputs, that affects calculations later

def check_existence(text):
    return bool(re.search(r'[A-Za-z\`\~\!\@\#\%\^\&\*\(\)\-\_\=\+\\\|\]\}\[\{\'\"\;\:\/\?\>\<]', text))

def check_existenceii(text):
    return bool(re.search(r'[\+\-\*\/\%\^\(\)]', text))

def check_existenceiii(text):
    return bool(re.search(r'[\`\~\!\@\#\&\_\=\\\|\]\}\[\{\'\"\;\:\?\>\<]', text))

# Following executes os commands after replacing any currency symbols in input

def execute_command(dc):
    start = textbuffer.get_start_iter()
    end = textbuffer.get_end_iter()
    if check_existence(textbuffer.get_text(start,end,"false")):
        result.set_text("Input Contains Non Numerical Characters")
    else:
        static_command = "echo " + textbuffer.get_text(start,end,"false").replace('\n', ' ').replace('\r', ' ').replace('$', '').replace(',', '').replace('؋', '').replace('.د.ب', '').replace('¢', '').replace('£', '').replace('¥', '').replace('৳', '').replace('฿', '').replace('៛', '').replace('₡', '').replace('₥', '').replace('₦', '').replace('₩', '').replace('₪', '').replace('₫', '').replace('€', '').replace('₭', '').replace('₮', '').replace('₱', '').replace('₲', '').replace('₴', '').replace('₹', '').replace('ƒ', '').replace('د.إ', '').replace('د.ت', '').replace('د.ع', '').replace('د.ك', '').replace('د.م.', '').replace('دج', '').replace('ر.س', '').replace('ر.ع.', '').replace('ر.ق', '').replace('ر.ي', '').replace('ل.د', '')
        full_command = static_command + dc
        proc = subprocess.Popen(full_command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True,universal_newlines=True)
        (out, err) = proc.communicate()
        # outwithoutreturn = out.rstrip('\n')
        if err:
            result.set_text("Input Contains Non Numerical Characters")
        else:
            result.set_text(out.rstrip('\n'))


def execute_commandii():
    start = textbuffer.get_start_iter()
    end = textbuffer.get_end_iter()
    if not check_existenceii(textbuffer.get_text(start,end,"false")):
        result.set_text("BM needs any of +,-,*,/,%,^,() operators")
    elif check_existenceiii(textbuffer.get_text(start,end,"false")):
        result.set_text("Input Contains Invalid Characters")
    else:
        full_command = "awk \"BEGIN {printf \\\"%." + str(spinbutton.get_value_as_int()) + "f\\\", " + textbuffer.get_text(start,end,"false").replace('\n', ' ').replace('\r', ' ').replace('$', '').replace(',', ',').replace('؋', '').replace('.د.ب', '').replace('¢', '').replace('£', '').replace('¥', '').replace('৳', '').replace('฿', '').replace('៛', '').replace('₡', '').replace('₥', '').replace('₦', '').replace('₩', '').replace('₪', '').replace('₫', '').replace('€', '').replace('₭', '').replace('₮', '').replace('₱', '').replace('₲', '').replace('₴', '').replace('₹', '').replace('ƒ', '').replace('د.إ', '').replace('د.ت', '').replace('د.ع', '').replace('د.ك', '').replace('د.م.', '').replace('دج', '').replace('ر.س', '').replace('ر.ع.', '').replace('ر.ق', '').replace('ر.ي', '').replace('ل.د', '') + "}\"" 
        proc = subprocess.Popen(full_command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True,universal_newlines=True)
        (out, err) = proc.communicate()
        # outwithoutreturn = out.rstrip('\n')
        if err:
            result.set_text("Input Contains Invalid Characters")
        else:
            result.set_text(out)

# Following functions creates folder, does filing and viewing of files

def create_directory(myfolder):
    try:
        os.makedirs(myfolder)
        # print "Successfully Created : " + myfolder
    except OSError as e:
        if e.errno != errno.EEXIST:
            result.set_text("Failed Creating quickcal Home Folder")


def fileit():
    from datetime import datetime
    datestring = datetime.strftime(datetime.now(), '%Y-%m-%d')
    try:

        f = open(path + '/' + 'Inputs_' + datestring + '.txt', 'a+')
        start = textbuffer.get_start_iter()
        end = textbuffer.get_end_iter()
        f.write ('\n' + '\n' + textbuffer.get_text(start,end,"false"))
        f.close()

        g = open(path + '/' + 'Results_' + datestring + '.txt', 'a+')
        g.write ('\n' + '\n' + result.get_text())
        g.close()

        result.set_text("Filed Successfully")

    except IOError:
        result.set_text("Failed Writing to Inputs / Results file")


def viewit(file):

    from datetime import datetime
    datestring = datetime.strftime(datetime.now(), '%Y-%m-%d')

    subprocess.call(["xdg-open", path + '/' + file + datestring + '.txt'])

    # if sys.platform == 'linux2':
        # subprocess.call(["xdg-open", path + '/' + file + datestring + '.txt'])
    # else:
        # os.startfile(path + '/' + file + datestring + '.txt')


class Handler: 

# Calculator buttons and their respective clicked actions. Calls the functions above with their respective parameters.

    def basicbutton(self, button): 
        execute_commandii()

    def sumbutton(self, button): 
        dynamic_command = " | awk '{ for(i=1; i<=NF;i++) j+=$i; printf \"%." + str(spinbutton.get_value_as_int()) + "f\", j; j=0 }'"
        execute_command(dynamic_command)

    def averagebutton(self, button): 
        dynamic_command = " | awk '{ for(i=1; i<=NF;i++) j+=$i; printf \"%." + str(spinbutton.get_value_as_int()) + "f\", j/NF; j=0 }'"
        execute_command(dynamic_command)

    def countbutton(self, button): 
        dynamic_command = " | awk '{ printf NF }'"
        execute_command(dynamic_command)

    def minimumbutton(self, button): 
        dynamic_command = " | awk '{m=$1;for(i=1;i<=NF;i++)if($i<m)m=$i;printf m}'"
        execute_command(dynamic_command)

    def maximumbutton(self, button): 
        dynamic_command = " | awk '{m=$1;for(i=1;i<=NF;i++)if($i>m)m=$i;printf m}'"
        execute_command(dynamic_command)

    def rangebutton(self, button): 
        dynamic_command = " | awk '{{min=max=$i};for(i=1;i<=NF;i++){if($i>max) {max=$i} if($i<min) {min=$i}} } END {printf \"%." + str(spinbutton.get_value_as_int()) + "f\", max-min}'"
        execute_command(dynamic_command)

    def stddevbutton(self, button): 
        dynamic_command = " | awk '{ A=0; V=0; for(N=1; N<=NF; N++) A+=$N ; A/=NF ; for(N=1; N<=NF; N++) V+=(($N-A)*($N-A))/(NF-1); printf \"%." + str(spinbutton.get_value_as_int()) + "f\", sqrt(V) }'"
        execute_command(dynamic_command)

    def comboboxtext1_changed(self, comboboxtext): 
        dynamic_command = " | num " + ourcomboboxtext.get_active_text() + " OFMT=\"%." + str(spinbutton.get_value_as_int()) + "f\""
        execute_command(dynamic_command)

    def clearbutton(self, button): 
        textbuffer.set_text("")
        result.set_text("")
        textview.grab_focus()

    def detailsbutton(self, button):
        ouraboutwindow.set_transient_for(window)
        ouraboutwindow.run()
        ouraboutwindow.hide()
        # ouraboutwindow.destroy()

    def fileitbutton(self, button):
        fileit()

    def view_todays_inputs_button(self, button):
        viewit("Inputs_")

    def view_todays_results_button(self, button):
        viewit("Results_")    


builder = Gtk.Builder() 
builder.add_from_file("/usr/lib/quickcal/quickcal.glade") 
builder.connect_signals(Handler()) 
window = builder.get_object("window1") 
textview = builder.get_object("textview1")
textbuffer = textview.get_buffer()
textview.modify_font(Pango.FontDescription('Sans-serif 14'))
ourcomboboxtext = builder.get_object("comboboxtext1")

# Following specifies the combo box text values and populates the same

default_text = ["Absolute-Value", "Coefficient-Of-Variance", "Count", "First", "Fourth-Moment-About-The-Mean", "Frequency-Maximum", "Frequency-Minimum", "Increment", "Interquartile-Range", "Is-Ascending", "Is-Descending", "Is-Non-Ascending", "Is-Non-Descending", "Is-Strictly-Ascending", "Is-Strictly-Descending", "Is-Unique", "Kurtosis", "Last", "Maximum", "Mean", "Mean-Absolute-Deviation", "Meanest", "Median", "Median-High", "Median-Low", "Minimum", "Mode-High", "Mode-Min", "Modes", "Normalize", "Population-Coefficient-Of-Variance", "Population-Kurtosis", "Population-Skewness", "Population-Standard-Deviation", "Population-Variance", "Product", "Quartile-0", "Quartile-1", "Quartile-2", "Quartile-3", "Quartile-4", "Range", "Round", "Round-Down", "Round-Off", "Round-Up", "Sample-Coefficient-Of-Variance", "Sample-Kurtosis", "Sample-Skewness", "Sample-Standard-Deviation", "Sample-Variance", "Second-Moment-About-The-Mean", "Sign", "Skewness", "Sort", "Sort-Ascending", "Sort-Descending", "Standard-Deviation", "Sum", "Sum-Of-Cubes", "Sum-Of-Quads", "Sum-Of-Squares", "Third-Moment-About-The-Mean", "Trimean", "Variance"]

for x in default_text:
    ourcomboboxtext.append_text(x)

spinbutton = builder.get_object("spinbutton1")    
result = builder.get_object("result1")
result.modify_font(Pango.FontDescription('Sans-serif 14'))
ouraboutwindow = builder.get_object("aboutdialog1")

# Following checks / creates the quickcal home folder

home=os.environ["HOME"]
path=os.path.join(home,"quickcal")
# print path
create_directory(path)

window.connect("delete-event", Gtk.main_quit) 
window.show_all() 
Gtk.main()