#!/usr/bin/env python
# encoding: utf-8
#
# Author: Maycon Sambinelli <msambinelli@gmail.com>

import getopt, sys
from PyQt4 import QtCore, QtGui
import tempfile
import pydot
import pdb

class ImageViewer(QtGui.QMainWindow):

    # adaptado de: http://ftp.ics.uci.edu/pub/centos0/ics-custom-build/BUILD/PyQt-x11-gpl-4.7.2/examples/widgets/imageviewer.py

    def __init__(self):
        super(ImageViewer, self).__init__()

        self.printer = QtGui.QPrinter()
        self.scaleFactor = 0.0

        self.imageLabel = QtGui.QLabel()
        self.imageLabel.setBackgroundRole(QtGui.QPalette.Base)
        self.imageLabel.setSizePolicy(QtGui.QSizePolicy.Ignored,
                QtGui.QSizePolicy.Ignored)
        self.imageLabel.setScaledContents(True)

        self.scrollArea = QtGui.QScrollArea()
        self.scrollArea.setBackgroundRole(QtGui.QPalette.Dark)
        self.scrollArea.setWidget(self.imageLabel)
        self.setCentralWidget(self.scrollArea)

        self.createActions()

        self.setWindowTitle("Graview v0.1")
        self.resize(700, 600)

    def open(self, fileName):

        if fileName:
            image = QtGui.QImage(fileName)
            if image.isNull():
                QtGui.QMessageBox.information(self, "Image Viewer",
                        "Cannot load %s." % fileName)
                return

            self.imageLabel.setPixmap(QtGui.QPixmap.fromImage(image))
            self.scaleFactor = 1.0

            self.printAct.setEnabled(True)
            self.fitToWindowAct.setEnabled(True)
            self.updateActions()

            if not self.fitToWindowAct.isChecked():
                self.imageLabel.adjustSize()

    def print_(self):
        dialog = QtGui.QPrintDialog(self.printer, self)
        if dialog.exec_():
            painter = QtGui.QPainter(self.printer)
            rect = painter.viewport()
            size = self.imageLabel.pixmap().size()
            size.scale(rect.size(), QtCore.Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
            painter.setWindow(self.imageLabel.pixmap().rect())
            painter.drawPixmap(0, 0, self.imageLabel.pixmap())

    def zoomIn(self):
        self.scaleImage(1.25)

    def zoomOut(self):
        self.scaleImage(0.8)

    def normalSize(self):
        self.imageLabel.adjustSize()
        self.scaleFactor = 1.0

    def fitToWindow(self):
        fitToWindow = self.fitToWindowAct.isChecked()
        self.scrollArea.setWidgetResizable(fitToWindow)
        if not fitToWindow:
            self.normalSize()

        self.updateActions()

    def about(self):
        QtGui.QMessageBox.about(self, "Graview v1.0",
                                "<p>Atalhos:</p>"
                                "<ul>"
                                "<li><strong>Ctrl++</strong>: Zoom in</li>"
                                "<li><strong>Ctrl+-</strong>: Zoom out</li>"
                                "<li><strong>Ctrl+0</strong>: Normal size</li>"
                                "<li><strong>Ctrl+P</strong>: Print</li>"
                                "<li><strong>Ctrl+F</strong>: Fit to the windown</li>"
                                "<li><strong>Ctrl+h</strong>: Show this help</li>"
                                "</ul>")
    def createActions(self):

        self.printAct = QtGui.QAction("&Print...", self, shortcut="Ctrl+P",
                enabled=False, triggered=self.print_)
        self.imageLabel.addAction(self.printAct)

        self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q",
                triggered=self.close)
        self.imageLabel.addAction(self.exitAct)

        self.zoomInAct = QtGui.QAction("Zoom &In (25%)", self,
                shortcut="Ctrl++", enabled=False, triggered=self.zoomIn)
        self.imageLabel.addAction(self.zoomInAct)

        self.zoomOutAct = QtGui.QAction("Zoom &Out (25%)", self,
                shortcut="Ctrl+-", enabled=False, triggered=self.zoomOut)
        self.imageLabel.addAction(self.zoomOutAct)

        self.normalSizeAct = QtGui.QAction("&Normal Size", self,
                shortcut="Ctrl+0", enabled=False, triggered=self.normalSize)
        self.imageLabel.addAction(self.normalSizeAct)

        self.fitToWindowAct = QtGui.QAction("&Fit to Window", self,
                enabled=False, checkable=True, shortcut="Ctrl+F",
                triggered=self.fitToWindow)
        self.imageLabel.addAction(self.fitToWindowAct)

        self.aboutAct = QtGui.QAction("&About", self, triggered=self.about, shortcut="Ctrl+h")
        self.imageLabel.addAction(self.aboutAct)

        self.aboutQtAct = QtGui.QAction("About &Qt", self,
                triggered=QtGui.qApp.aboutQt)
        self.imageLabel.addAction(self.aboutQtAct)

    def updateActions(self):
        self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked())

    def scaleImage(self, factor):
        self.scaleFactor *= factor
        self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size())

        self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
        self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)

        self.zoomInAct.setEnabled(self.scaleFactor < 3.0)
        self.zoomOutAct.setEnabled(self.scaleFactor > 0.333)

    def adjustScrollBar(self, scrollBar, factor):
        scrollBar.setValue(int(factor * scrollBar.value()
                                + ((factor - 1) * scrollBar.pageStep()/2)))

def graph_load(path, is_oriented, show_weight):

    file = open(path, "r")
    lines = file.readlines()

    """
    O header consiste de uma linha com dois números inteiros: o
    primeiro é o número de vértices e o segundo o número de arestas
    """
    header = lines[0].strip().split()
    n = int(header[0])
    m = int(header[1])

    gtype = 'graph'
    if is_oriented:
        gtype = 'digraph'

    graph = pydot.Dot(graph_type = gtype)

    vertices = []
    for i in range(n):
        vertices.append(pydot.Node(str(i)))
        graph.add_node(vertices[i])

    for i in range(1, m + 1):
        line = lines[i].strip().split()
        u = int(line[0])
        v = int(line[1])

        if show_weight and len(line) > 2:
            e = pydot.Edge(vertices[u], vertices[v], label= line[2])
        else:
            e = pydot.Edge(vertices[u], vertices[v])
        graph.add_edge(e)
    return graph

def usage():
     print "USAGE: %s [options] input_file" % sys.argv[0]
     print "Options:"
     print "    -h Show this menu"
     print "    -d Input graph is oriented"
     print "    -w Input graph is  weighted"
     print ""
     print "Keyboard shortcuts:"
     print "    Ctrl++ Zoom in"
     print "    Ctrl+- Zoom out"
     print "    Ctrl+0 Normal view"
     print "    Ctrl+p Print"
     print "    Ctrl+f Fit into the windown"
     print "    Ctrl+h Show help"
     sys.exit(1)

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hwd")
    except getopt.GetoptError as err:
        print str(err)
        usage()
        sys.exit(2)

    show_weight = False
    digraph = False
    for o, a in opts:
        if o == "-w":
            show_weight = True
        elif o == "-d":
            digraph = True
        elif o == "-h":
            usage()
        else:
            assert False, "unhandled option"

    if len(args) != 1:
        usage();

    graph = graph_load(args[0], digraph, show_weight)
    file = tempfile.NamedTemporaryFile(delete= False)
    file.close()

    graph.write_png(file.name)

    app = QtGui.QApplication(sys.argv)
    imageViewer = ImageViewer()
    imageViewer.open(file.name)
    imageViewer.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
