#
# Copyright (c) 2004 Art Haas
#
# This file is part of PythonCAD.
#
# PythonCAD 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.
#
# PythonCAD 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 PythonCAD; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# code for setting printing parameters
#

import pygtk
pygtk.require('2.0')
import gtk

import os
import tempfile

from PythonCAD.Generic.plotfile import Plot
from PythonCAD.Generic.printing import PSPlot

def _toggle_widgets_on(widget):
    widget.set_sensitive(gtk.TRUE)

def _toggle_widgets_off(widget):
    widget.set_sensitive(gtk.FALSE)

def _print_rb_cb(button, hbox):
    if button.get_active():
        hbox.foreach(_toggle_widgets_on)
    else:
        hbox.foreach(_toggle_widgets_off)
    return gtk.TRUE

def _error_dialog(gtkimage, errmsg):
    _window = gtkimage.getWindow()
    _dialog = gtk.MessageDialog( _window,
                                 gtk.DIALOG_DESTROY_WITH_PARENT,
                                 gtk.MESSAGE_ERROR,
                                 gtk.BUTTONS_CLOSE,
                                 errmsg)
    _dialog.run()
    _dialog.destroy()

def print_dialog(gtkimage, plot):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Printing Preferences", _window,
                         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                         (gtk.STOCK_OK, gtk.RESPONSE_OK,
                          gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
    _vbox = _dialog.vbox
    #
    _psplot = PSPlot(plot)
    #
    # options for all plots
    #
    _frame = gtk.Frame("Plot Options")
    _fvbox = gtk.VBox(gtk.FALSE, 5)
    _fvbox.set_border_width(5)
    _frame.add(_fvbox)
    _ccb = gtk.CheckButton("Print in Color")
    _fvbox.pack_start(_ccb, gtk.FALSE, gtk.FALSE, 5)
    _icb = gtk.CheckButton("Print White as Black")
    _fvbox.pack_start(_icb, gtk.FALSE, gtk.FALSE, 5)
    _lcb = gtk.CheckButton("Print in Landscape Mode")
    _fvbox.pack_start(_lcb, gtk.FALSE, gtk.FALSE, 5)
    _hbox = gtk.HBox(gtk.FALSE, 5)
    _fvbox.pack_start(_hbox, gtk.TRUE, gtk.TRUE, 5)
    _label = gtk.Label("Paper Size:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _menu = gtk.Menu()
    _papersizes = _psplot.getPaperSizes()
    _papersizes.sort()
    for _size in _papersizes:
        _item = gtk.MenuItem(_size)
        _menu.append(_item)
    _size_menu = gtk.OptionMenu()
    _size_menu.set_menu(_menu)
    _size_menu.set_history(0) # perhaps a global preference value?
    _hbox.pack_start(_size_menu, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    #
    #
    _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _frame = gtk.Frame("Print Destination")
    _fvbox = gtk.VBox(gtk.FALSE, 5)
    _fvbox.set_border_width(5)
    _frame.add(_fvbox)
    #
    _phbox = gtk.HBox(gtk.FALSE, 5)
    _label = gtk.Label("Printer:")
    _label_size_group.add_widget(_label)
    _phbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _print_entry = gtk.Entry()
    _print_entry.set_text("lp")
    _phbox.pack_start(_print_entry, gtk.FALSE, gtk.FALSE, 5)
    _fvbox.pack_start(_phbox, gtk.FALSE, gtk.FALSE, 5)
    #
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _label = gtk.Label("File:")
    _label_size_group.add_widget(_label)
    _label.set_sensitive(gtk.FALSE)
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _file_entry = gtk.Entry()
    _file_entry.set_sensitive(gtk.FALSE)
    _fhbox.pack_start(_file_entry, gtk.FALSE, gtk.FALSE, 5)
    _fvbox.pack_start(_fhbox, gtk.FALSE, gtk.FALSE, 5)
    #
    _hbox = gtk.HBox(gtk.FALSE, 5)
    _label = gtk.Label("Send print to ...")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _prb = gtk.RadioButton()
    _prb.set_label("Printer")
    _prb.set_mode(gtk.TRUE)
    _prb.connect("toggled", _print_rb_cb, _phbox)
    _hbox.pack_start(_prb, gtk.FALSE, gtk.FALSE, 5)
    _frb = gtk.RadioButton(_prb)
    _frb.set_label("File")
    _frb.set_mode(gtk.TRUE)
    _frb.connect("toggled", _print_rb_cb, _fhbox)
    _hbox.pack_start(_frb, gtk.FALSE, gtk.FALSE, 5)
    _fvbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 5)
    #
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    _dialog.show_all()
    while True:
        _response = _dialog.run()
        if _response == gtk.RESPONSE_OK:
            plot.setColorMode(_ccb.get_active())
            plot.invertWhite(_icb.get_active())
            plot.setLandscapeMode(_lcb.get_active())
            plot.getPlotData()
            _psplot.setSize(_papersizes[_size_menu.get_history()])
            if _prb.get_active(): # send job out
                try:
                    _f = tempfile.NamedTemporaryFile()
                    _fname = _f.name
                    try:
                        try:
                            _psplot.write(_f)
                            _cmd = "%s %s" %(_print_entry.get_chars(0, -1), _fname)
                            try:
                                _res = os.system(_cmd)
                                if _res == 0:
                                    break
                                else:
                                    _msg = "Non-zero exit status from '%s': %d" % (_cmd, _res)
                                    _error_dialog(gtkimage, _msg)
                            except StandardError, _err:
                                _msg = "Error executing command '%s': %s" % (_cmd, _err)
                                _error_dialog(gtkimage, _msg)
                        except StandardError, _err:
                            _msg = "Error writing '%s': %s" % (_fname, _err)
                            _error_dialog(gtkimage, _msg)
                    finally:
                        _f.close()
                except StandardError, _err:
                    _msg = "Error creating temporary file %s" % _err
                    _error_dialog(gtkimage, _msg)
            else:
                _fname = _file_entry.get_chars(0, -1)
                try:
                    _f = file(_fname, "w")
                    try:
                        _psplot.write(_f)
                    finally:
                        _f.close()
                        break
                except StandardError, _err:
                    _msg = "Error writing to %s: %s" % (_fname, _err)
                    _error_dialog(gtkimage, _msg)
        else:
            break
    _psplot.finish()        
    _dialog.destroy()

def _show_print_dialog(gtkimage, tool):
    _plot = Plot(gtkimage)
    _x1, _y1 = tool.getFirstCorner()
    _x2, _y2 = tool.getSecondCorner()
    _xmin = min(_x1, _x2)
    _ymin = min(_y1, _y2)
    _xmax = max(_x1, _x2)
    _ymax = max(_y1, _y2)
    _plot.setBounds(_xmin, _ymin, _xmax, _ymax)
    tool.reset()
    plot_mode_init(gtkimage, tool)
    gtkimage.redraw() # yuck ...
    print_dialog(gtkimage, _plot)

def plot_motion_notify(gtkimage, widget, event, tool):
    _tx, _ty = tool.getFirstCorner()
    _px, _py = gtkimage.coordToPixTransform(_tx, _ty)
    _gc = gtkimage.getGC()
    _x = int(event.x)
    _y = int(event.y)
    _cp = tool.getCurrentPoint()
    if _cp is not None:
        _xc, _yc = _cp
        _xmin = min(_xc, _px)
        _ymin = min(_yc, _py)
        _rw = abs(_xc - _px)
        _rh = abs(_yc - _py)
        widget.window.draw_rectangle(_gc, gtk.FALSE, _xmin, _ymin, _rw, _rh)
    tool.setCurrentPoint(_x, _y)
    _xmin = min(_x, _px)
    _ymin = min(_y, _py)
    _rw = abs(_x - _px)
    _rh = abs(_y - _py)
    widget.window.draw_rectangle(_gc, gtk.FALSE, _xmin, _ymin, _rw, _rh)

def _make_tuple(text):
    try:
        _tpl = eval(text)
    except:
        raise StandardError, "Invalid point: " + text
    if not isinstance(_tpl, tuple):
        raise TypeError, "Invalid point: " + str(_tpl)
    if len(_tpl) != 2:
        raise ValueError, "Invalid point: " + str(_tpl)
    return _tpl

def plot_second_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    tool.setSecondCorner(_x, _y)
    _show_print_dialog(gtkimage, tool)

def plot_second_entry_event_cb(gtkimage, widget, tool):
    _entry = gtkimage.getEntry()
    _text = _entry.get_chars(0,-1)
    _entry.delete_text(0,-1)
    if len(_text):
        _x, _y = _make_tuple(_text)
        tool.setSecondCorner(_x, _y)
        _show_print_dialog(gtkimage, tool)

def plot_first_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    tool.setFirstCorner(_x, _y)
    gtkimage.setPrompt("Click in the drawing area or enter another point.")
    tool.setHandler("button_press", plot_second_button_press_cb)
    tool.setHandler("entry_event", plot_second_entry_event_cb)
    tool.setHandler("motion_notify", plot_motion_notify)
    gtkimage.getGC().set_function(gtk.gdk.INVERT)
        
def plot_first_entry_event_cb(gtkimage, widget, tool):
    _entry = gtkimage.getEntry()
    _text = _entry.get_chars(0,-1)
    _entry.delete_text(0,-1)
    if len(_text):
        _x, _y = _make_tuple(_text)
        tool.setFirstCorner(_x, _y)
        gtkimage.setPrompt("Click in the drawing area or enter another point.")
        tool.setHandler("button_press", plot_second_button_press_cb)
        tool.setHandler("entry_event", plot_second_entry_event_cb)
        tool.setHandler("motion_notify", plot_motion_notify)
        gtkimage.getGC().set_function(gtk.gdk.INVERT)

def plot_mode_init(gtkimage, tool):
    gtkimage.setPrompt("Click in the drawing area or enter a point.")
    tool.setHandler("initialize", plot_mode_init)
    tool.setHandler("button_press", plot_first_button_press_cb)
    tool.setHandler("entry_event", plot_first_entry_event_cb)
