import os, sys

from os.path import join, basename, splitext, normpath, abspath

from string import Template
import logging
import unittest

# intitalize logging module
log = logging.getLogger("test_graphparser")
console = logging.StreamHandler()
console.setLevel(logging.WARNING)
# set a format which is simpler for console use
formatter = logging.Formatter('%(levelname)-8s %(message)s')
# tell the handler to use this format
console.setFormatter(formatter)
log.addHandler(console)

#LOG_FILENAME = splitext(__file__)[0]+'.log'
#hdlr = logging.FileHandler(LOG_FILENAME)
#log.addHandler(hdlr)
#formatter = logging.Formatter('%(levelname)-8s %(message)s')
#hdlr.setFormatter(formatter)
#log.setLevel(logging.INFO)

# Directory with test files
BASE_DIR = join(abspath(os.path.dirname(__file__)), "")
TESTFILES_DIR = "testgraphs/"
TESTFILES_PATH = join(BASE_DIR, TESTFILES_DIR)
DEST_DIR = join(BASE_DIR, 'tmp/')


def runcmd(syscmd):
    #err = os.system(syscmd)
    sres = os.popen(syscmd)
    resdata = sres.read()
    err = sres.close()
    if err:
        log.warning('Failed to run command:\n%s', syscmd)
        log.debug('Output:\n%s', resdata)
    return err


def meps(filename):
    fn = splitext(filename)[0]
    s = "latex -halt-on-error -interaction nonstopmode %s.tex" % fn
    err = runcmd(s)
    if err: return err
    if sys.platform == 'win32':
        s = "dvips -Ppdf -G0 -D600 -E* -o%s.eps %s.dvi" % (fn, fn)
        err = runcmd(s)
        if err: return err
        s = "epstool --bbox --copy --output %s_tmp.eps %s.eps" % (fn, fn)
        err = runcmd(s)
        if err: return err
        try:
            os.remove("%s.eps" % fn)
            os.remove("%s.dvi" % fn)
            os.remove("%s.aux" % fn)
            os.remove("%s.log" % fn)
        #os.remove("%s.pgf" % fn)

        except:
            raise
        os.rename("%s_tmp.eps" % fn, "%s.eps" % fn)
        s = "epstopdf %s.eps" % fn
        err = runcmd(s)
    else:
        s = "dvips %s.dvi" % fn
        err = runcmd(s)
        s = "ps2eps -B -f %s.ps" % fn
        err = runcmd(s)
        if err: return err
        s = "epstopdf %s.eps" % fn
        err = runcmd(s)

    return err


testdotfile = normpath(join(BASE_DIR, 'testgraphs/', 'concentrate.dot'))

textemplate = r"""
\documentclass{article}
\usepackage{tikz}

\usepackage{verbatim}
\usepackage[active,tightpage]{preview}
\setlength\PreviewBorder{0pt}%
\PreviewEnvironment{tikzpicture}

\begin{document}
\begin{tikzpicture}
\matrix[every node/.style={draw=black!20}] (mtrx) {
\node[label=below:original] {\includegraphics{$testfile}}; & \node[label=below:tikz] {\includegraphics{${testfile}_tikz}};\\
\node[label=below:pgf] {\includegraphics{${testfile}_pgf}}; & \node[label=below:pst] {\includegraphics{${testfile}_pst}};\\
};
\node[above] at (mtrx.north) {$testfile};
\end{tikzpicture}
\end{document}
"""

s = Template(textemplate)


def create_pdf(texfile, use_pdftex=True):
    if not splitext(texfile)[1]:
        fn = basename(texfile) + '.tex'
    else:
        fn = basename(texfile)
    if sys.platform == 'win32':
        syscmd = 'texify --pdf --clean %s' % (fn)
    else:
        syscmd = 'pdflatex -halt-on-error -interaction nonstopmode %s' % (fn)
    err = runcmd(syscmd)
    return err


def create_original(dotfilename):
    # Process the file with dot and create a pdf
    #   dot -Tps2 file.dot > file.ps
    #   ps2pdf file.ps
    basefn = basename(dotfilename)
    destfile = normpath(join(DEST_DIR, splitext(basefn)[0]))
    cwd = os.getcwd()
    os.chdir(os.path.dirname(destfile))
    syscmd = 'dot -Tps2 %s > %s.ps' % (dotfilename, destfile)
    err = runcmd(syscmd)
    syscmd = 'ps2pdf %s.ps' % (destfile)
    #os.remove("%s.ps" % destfile)
    err = runcmd(syscmd)
    os.chdir(cwd)
    return err


def create_tikz(dotfilename):
    basefn = basename(dotfilename)
    destfile = normpath(join(DEST_DIR, splitext(basefn)[0])) + '_tikz'
    syscmd = 'dot2tex -ftikz --crop %s > %s.tex' % (dotfilename, destfile)
    err = runcmd(syscmd)
    cwd = os.getcwd()
    os.chdir(os.path.dirname(destfile))
    err = create_pdf(destfile)
    #os.remove(destfile)
    os.chdir(cwd)
    return err


def create_pgf(dotfilename):
    basefn = basename(dotfilename)
    destfile = normpath(join(DEST_DIR, splitext(basefn)[0])) + '_pgf'
    syscmd = 'dot2tex --crop %s > %s.tex' % (dotfilename, destfile)
    err = runcmd(syscmd)
    cwd = os.getcwd()
    os.chdir(os.path.dirname(destfile))
    err = create_pdf(destfile)
    #os.remove(destfile)
    os.chdir(cwd)
    return err


def create_pst(dotfilename):
    basefn = basename(dotfilename)
    destfile = normpath(join(DEST_DIR, splitext(basefn)[0])) + '_pst'
    syscmd = 'dot2tex -fpst %s > %s.tex' % (dotfilename, destfile)
    err = runcmd(syscmd)
    cwd = os.getcwd()
    os.chdir(os.path.dirname(destfile))
    #syscmd = 'meps %s' % (basename(destfile))
    #err = runcmd(syscmd)
    err = meps(basename(destfile))
    os.chdir(cwd)
    return err


def create_comparefile(dotfilename):
    basefn = basename(dotfilename)
    destfile = normpath(join(DEST_DIR, splitext(basefn)[0])) + '_cmp.tex'
    f = open(destfile, 'w')
    f.write(s.substitute(testfile=splitext(basefn)[0]))
    f.close()
    cwd = os.getcwd()
    os.chdir(os.path.dirname(destfile))
    err = create_pdf(destfile)
    #if sys.platform=='win32':
    #    syscmd = "start %s" % splitext(basename(destfile))[0]+'.pdf'
    #    err = runcmd(syscmd)

    os.chdir(cwd)


# Get a dot file to test

# Create a tikz version
# create a pgf version
# create a pstricks version
# Combine the images in a latex file

def compare_output(testdotfile):
    err = create_original(testdotfile)
    if err: return err
    err = create_tikz(testdotfile)
    if err: return err
    err = create_pgf(testdotfile)
    if err: return err
    err = create_pst(testdotfile)
    if err: return err
    err = create_comparefile(testdotfile)
    return err


# From
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/541096
def confirm(prompt=None, resp=False):
    """prompts for yes or no response from the user. Returns True for yes and
    False for no.

    'resp' should be set to the default value assumed by the caller when
    user simply types ENTER.

    >>> confirm(prompt='Create Directory?', resp=True)
    Create Directory? [y]|n:
    True
    >>> confirm(prompt='Create Directory?', resp=False)
    Create Directory? [n]|y:
    False
    >>> confirm(prompt='Create Directory?', resp=False)
    Create Directory? [n]|y: y
    True

    """

    if prompt is None:
        prompt = 'Confirm'

    if resp:
        prompt = '%s [%s]|%s: ' % (prompt, 'y', 'n')
    else:
        prompt = '%s [%s]|%s: ' % (prompt, 'n', 'y')

    while True:
        ans = raw_input(prompt)
        if not ans:
            return resp
        if ans not in ['y', 'Y', 'n', 'N']:
            print 'please enter y or n.'
            continue
        if ans == 'y' or ans == 'Y':
            return True
        if ans == 'n' or ans == 'N':
            return False


def run_rendertest(dotfile):
    print "Processing %s" % dotfile
    err = compare_output(normpath(join(TESTFILES_PATH, dotfile)))
    if err:
        return False
    else:
        return True
    s = "Is %s correct?" % (dotfile)
    return confirm(s, resp=True)


class RenderTest(unittest.TestCase):
    cmplist = []

    def setUp(self):
        if not os.path.exists(DEST_DIR):
            os.mkdir(DEST_DIR)

    def test_autosize(self):
        fn = 'autosize.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_compassports(self):
        fn = 'compassports.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_concentrate(self):
        fn = 'concentrate.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_escstr(self):
        fn = 'escstr.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_invis(self):
        fn = 'invis.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_nodenames(self):
        fn = 'nodenames.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_colors(self):
        fn = 'colors.dot'
        self.failUnless(run_rendertest(fn))
        self.cmplist.append(fn)

    def test_zzzzzzzzzzzfinal(self):
        os.chdir(DEST_DIR)
        flist = []
        for dotfile in self.cmplist:
            basefn = basename(dotfile)
            flist.append(normpath(join(splitext(basefn)[0])) + '_cmp.pdf')
        s = "pdftk %s cat output testrenders.pdf dont_ask" % " ".join(flist)
        err = runcmd(s)
        self.failIf(err)
        if sys.platform == 'win32':
            syscmd = "start %s" % 'testrenders.pdf'
            err = runcmd(syscmd)
        print "Check testrenders.pdf manually"


testdotfile2 = normpath(join(TESTFILES_PATH, 'compassports.dot'))

if __name__ == '__main__':
    #compare_output(testdotfile2)
    unittest.main()
