#!/usr/bin/env python
#
# Clarence - programmer's calculator
#
# Copyright (C) 2002 Tomasz Mka <p@ll.pl>
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

import os, sys, string
import gtk, GDK

from math import *


version = "0.1.8"

config = gui = {}
labels = ("DEC   =>", "HEX   =>", "OCT   =>", "ASCII =>", "BIN   =>")
entries = ("entry_dec", "entry_hex", "entry_oct", "entry_asc", "entry_bin")

#------------------------------------------------------------

def main_menu(action, widget):
	if action == 1:
		gui["main_entry"].set_text("")
	elif action == 2:
		gtk.mainquit()

def insert_menu(action, widget):
	if action == 1:
		gui["main_entry"].append_text('bin("")')
		gui["main_entry"].set_position(len(gui["main_entry"].get_text())-2)
	elif action == 2:
		gui["main_entry"].append_text('asc("")')
		gui["main_entry"].set_position(len(gui["main_entry"].get_text())-2)
	elif action == 3:
		gui["main_entry"].append_text('ans()')

def select_menu(action, widget):
	if action < 6:
		gui[entries[action-1]].select_region(0, len(gui[entries[action-1]].get_text()))
	else:
		for i in range(5):
			gui[entries[i]].select_region(0, 0)
		gui["main_entry"].grab_focus()

def functions_menu(action, widget):
	if action == 1:
		gui["main_entry"].append_text('veclen(,,,)')
		gui["main_entry"].set_position(len(gui["main_entry"].get_text())-4)

def help_menu(action, widget):
	if action == 1:
		warning_window("About", "====================================="
        "\nClarence (programmer's calculator)\n"
        "\nversion v" + version +"\n\n"
        "http://nrn.ll.pl/pasp/clarence.html\n"
        "====================================="
        "\n\nwritten by Tomasz Maka <p@ll.pl>\n")

#------------------------------------------------------------

def warning_window_close(*args):
	gui["warning_window"].hide()
	gui["main_window"].set_sensitive(gtk.TRUE)
	gui["main_entry"].grab_focus()

def warning_window(title, message):
	win = gtk.GtkWindow()
	gui["warning_window"]=win
	win.set_policy(gtk.TRUE, gtk.TRUE, gtk.FALSE)
	win.set_title(title)
	win.set_usize(300, -2)
	win.connect("delete_event", warning_window_close)
	win.set_border_width(4)

	win.set_position(gtk.WIN_POS_CENTER)

	box1 = gtk.GtkVBox(spacing=5)
	win.add(box1)
	box1.show()

	label = gtk.GtkLabel("\n\n" + message + "\n\n")
	set_font(label)
	label.show()
#	box1.pack_start(label, expand=gtk.FALSE)
	box1.pack_start(label)

	button = gtk.GtkButton("Close")
	button.connect("clicked", warning_window_close)
	box1.pack_start(button, expand=gtk.FALSE)
	button.set_flags(gtk.CAN_DEFAULT)
	button.grab_default()
	button.show()

	gui["main_window"].set_sensitive(gtk.FALSE)
	gui["warning_window"].show()

#------------------------------------------------------------

def create_main_window(*args):
	win = gtk.GtkWindow()
	gui["main_window"]=win
	win.set_policy(gtk.TRUE, gtk.TRUE, gtk.FALSE)
	win.set_title("Clarence v" + version)
	win.set_usize(config["win_width"], config["win_height"])
#	win.set_uposition(config["win_pos_x"], config["win_pos_y"])
	win.connect("delete_event", gtk.mainquit)
	win.set_border_width(4)

	win.set_position(gtk.WIN_POS_CENTER)

	box1 = gtk.GtkVBox(spacing=5)
	win.add(box1)
	box1.show()

	ag = gtk.GtkAccelGroup()
	itemf = gtk.GtkItemFactory(gtk.GtkMenuBar, "<main>", ag)
	gui["main_window"].add_accel_group(ag)
	itemf.create_items([
		('/_Misc',                      None,               None,           0, '<Branch>'),
		('/_Misc/_Clear',               'Escape',           main_menu,      1, ''),
		('/_Misc/sep1',                 None,               None,           0, '<Separator>'),
		('/_Misc/E_xit',                '<alt>X',           main_menu,      2, ''),
		('/_Insert',                    None,               None,           0, '<Branch>'),
		('/_Insert/_Bin value',         '<control>comma',   insert_menu,    1, ''),
		('/_Insert/_ASCII chars',       '<control>period',  insert_menu,    2, ''),
		('/_Insert/_Last result',       '<control>slash',   insert_menu,    3, ''),
		('/_Select',                    None,               None,           0, '<Branch>'),
		('/_Select/_Decimal field',     '<control>1',       select_menu,    1, ''),
		('/_Select/_Hexadecimal field', '<control>2',       select_menu,    2, ''),
		('/_Select/_Octal field',       '<control>3',       select_menu,    3, ''),
		('/_Select/_ASCII field',       '<control>4',       select_menu,    4, ''),
		('/_Select/_Binary field',      '<control>5',       select_menu,    5, ''),
		('/_Select/sep1',               None,               None,           0, '<Separator>'),
		('/_Select/_Clear fields',      '<control>0',       select_menu,    6, ''),
		('/F_unctions',                 None,               None,           0, '<Branch>'),
		('/F_unctions/_Vector lenght',  None,               functions_menu, 1, ''),
		('/_Help',                      None,               None,           0, '<LastBranch>'),
		('/_Help/_About',               None,               help_menu,      1, '')
	])
	menubar = itemf.get_widget('<main>')
	box1.pack_start(menubar, expand=gtk.FALSE)
	menubar.show()

	entry = gtk.GtkEntry()
	gui["main_entry"] = entry
	box1.pack_start(entry, expand=gtk.FALSE)
	set_font(entry)
	entry.set_text(config["last_expression"])
	entry.connect("key_press_event", key_function)
	entry.grab_focus()
	gui["main_entry"].show()

	frame = gtk.GtkFrame()
	box1.pack_start(frame)
	frame.show()

	box2 = gtk.GtkVBox()
	frame.add(box2)
	box2.show()

	table = gtk.GtkTable(2, 5, gtk.FALSE)
	table.set_row_spacings(5)
	table.set_col_spacings(5)
	table.set_border_width(10)
#	box2.pack_start(table, expand=gtk.FALSE)
	box2.pack_start(table)
	table.show()

	for y in range(5):
		label = gtk.GtkLabel(labels[y])
		set_font(label)
		label.show()
		table.attach(label, 0,1, y,y+1)
		entry = gtk.GtkEntry()
		gui[entries[y]] = entry
		entry.set_editable(gtk.FALSE)
		entry.set_usize(260, -2)
		set_font(entry)
		entry.show()
		table.attach(entry, 1,2, y,y+1)

	gui["main_window"].show()

#	print win.get_window().x
#	print win.get_window().y
#	print gtk._root_window().get_position()

	result(config["last_expression"])

#------------------------------------------------------------

def getachr(value):
	if (value>=32) and (value<=255):
		return value
	else:
		return "."

#------------------------------------------------------------
# functions

def veclen(x0,y0,x1,y1):
	return sqrt((x1-x0)**2 + (y1-y0)**2)

#------------------------------------------------------------

def bin(value):
	result=0
	for i in range(len(value)):
		if (value[i]!="0" and value[i]!="1"):
			return 0
	for i in range(len(value)):
		if (i>=32):
			return 0
		result=result+((ord(value[len(value)-1-i])-ord("0")) * 1<<i)
	return result

#------------------------------------------------------------

def asc(value):
	result=0
	for i in range(len(value)):
		if (i<4):
			result=result+(ord(value[len(value)-1-i]) * 256**i)
	return result

#------------------------------------------------------------

def ans():
	return eval(gui["entry_dec"].get_text())

#------------------------------------------------------------

def result(value):
	if (value):
		try:
			resl=eval(value)
			resli=int(resl)
		except NameError:
			warning_window("Warning", "Function not found!")
			return 0
		except SyntaxError:
			warning_window("Warning", "Wrong syntax!")
			return 0
		except TypeError:
			warning_window("Warning", "Wrong syntax!")
			return 0
		except ZeroDivisionError:
			warning_window("Warning", "Division by zero!")
			return 0
		except OverflowError:
			warning_window("Warning", "Overflow detected!")
			return 0
	else:
		resl=0
		resli=0
	r_dec = str(resl)
	gui["entry_dec"].set_text(r_dec)
	r_hex = str(hex(resli))
	gui["entry_hex"].set_text(r_hex)
	r_oct = str(oct(resli))
	gui["entry_oct"].set_text(r_oct)
	r_asc="%c%c%c%c" % (getachr((resli>>24) & 255),
    getachr((resli>>16) & 255),
    getachr((resli>>8) & 255), getachr(resli & 255))
	gui["entry_asc"].set_text(r_asc)
	r_bin=""
	for i in range(32):
		k = 31 - i
		chrr=chr(ord("0")+((resli>>k) & 1))
		r_bin=r_bin+chrr
		if (k==8) or (k==16) or (k==24):
			r_bin=r_bin+"."
	gui["entry_bin"].set_text(r_bin)

#------------------------------------------------------------

def set_font(widget):
	style = widget.get_style().copy()
	style.font = gui["fixed_font"]
	widget.set_style(style)

#------------------------------------------------------------
    
def key_function(entry, event):
	if event.keyval == GDK.Return:
		result(entry.get_text())

#------------------------------------------------------------

def pcalc_get_cfg_dir():
	cfg_dir = os.environ["HOME"]
	cfg_dir = cfg_dir + os.sep + ".clay" + os.sep
	return cfg_dir

#------------------------------------------------------------

def pcalc_get_cfg_file():
	return pcalc_get_cfg_dir() + "pcalc"

#------------------------------------------------------------

def pcalc_check_config():
	cfg_dir = os.environ["HOME"]
	cfg_dir = cfg_dir + os.sep + ".clay" + os.sep
	cfg_file = cfg_dir + "pcalc"
	if not os.access(cfg_dir, os.F_OK):
		os.mkdir(cfg_dir)
	if not os.access(cfg_file, os.F_OK):
		f = open(cfg_file, "w")
		f.write("win_pos_x=0\n")
		f.write("win_pos_y=0\n")
		f.write("win_width=360\n")
		f.write("win_height=300\n")
		f.write("last_expression=")
		f.flush()
		f.close()

#------------------------------------------------------------

def pcalc_read_config():
	f_lines = open(pcalc_get_cfg_file(), 'r').readlines()
	for line in f_lines:
		fields = string.split(line, '=')
#		if (fields[0] == "win_pos_x"):
#			config["win_pos_x"] = string.atoi(fields[1])
#		if (fields[0] == "win_pos_y"):
#			config["win_pos_y"] = string.atoi(fields[1])
		if (fields[0] == "win_width"):
			config["win_width"] = string.atoi(fields[1])
		if (fields[0] == "win_height"):
			config["win_height"] = string.atoi(fields[1])
		if (fields[0] == "last_expression"):
			config["last_expression"] = fields[1]

#------------------------------------------------------------

def pcalc_write_config():
	if gui["main_window"].get_window():
		config["win_width"]=gui["main_window"].get_window().width
		config["win_height"]=gui["main_window"].get_window().height
	config["last_expression"]=string.replace(gui["main_entry"].get_text(), "ans()", "0")
	f = open(pcalc_get_cfg_file(), "w")
#	f.write("win_pos_x=%d\n" % config["win_pos_x"])
#	f.write("win_pos_y=%d\n" % config["win_pos_y"])
	f.write("win_width=%d\n" % config["win_width"])
	f.write("win_height=%d\n" % config["win_height"])
	f.write("last_expression=%s" % config["last_expression"])
	f.flush()
	f.close()

#------------------------------------------------------------

def main():
	gui["fixed_font"] = gtk.load_font("fixed")
	pcalc_check_config()
	pcalc_read_config()
	create_main_window()
	gtk.mainloop()
	pcalc_write_config()

if __name__ == '__main__': main()

