#!/usr/bin/env python3
# (c) 2019 duane a. bailey
"""
This collection of utilities eliminates the need for scripts in ambrosia.
The module is not automatically imported with ambrosia, but is imported
as needed.
"""
import os
import sys

def uniqueIdString(model):
    """Return a unique number that changes several hundred times per second.
    These numbers increase over the day.
    """
    idfile = model+".id"
    id = 0
    if os.path.exists(idfile):
        with open(idfile) as idf:
            lines = list(idf)
            if lines:
                id = 1+int(lines[0].strip())
    with open(idfile,'w') as idf:
        ids = '{:05d}'.format(id)
        idf.writelines([ids+'\n'])
    return ids

def pathOf(utility):
    """Determine and return the full path of a unix command, or None."""
    f = list(os.popen('type {}'.format(utility)))
    if not f:
        return None
    return f[0].split()[-1]

execs = { e : pathOf(e) for e in ['bash', 'convert', 'ffmpeg', 'less', 'povray',
           'composite', 'mogrify', 'python3']}

def removeFiles(*filenames):
    """Remove each of the files associated with the filenames.  Exceptions are quietly ignored.
    Similar to 'rm -f <filenames>' in unix.
    """
    for filename in filenames:
        if filename and os.path.exists(filename):
            try:
                os.unlink(filename)
            except:
                pass

def povray(model,runlog):
    """In the folder/directory 'projectFolder', render the POV file 'model.pov' to the image 'model.png'.
    If errors are encountered, POV log is written to 'model.log'.

    For ambrosia, we perform all rendering in the project folder.  This folder is populated
    with a number of files *before* POV is run:
        <inifile> -- a file containing POV runtime parameters, including
                     camera positioning, etc.
        <infile> -- the POV source code that generates the rendering.
    These files are generated by POV:
        <povoutfile> -- the POV output; the rendered image.  This is always a .png file,
                        other file types are converted post facto.
        <logfile> -- the log file associated with POV run.
    """
    projectf = os.path.dirname(model)
    infile = model+".pov"
    inifile = model+".ini"
    outfile = model+".png"
    logfile = model+".log"
    cmd = 'cd "{}"; "{}" 2>/dev/null +I"{}" +FN +O"{}" +GA"{}" "{}"'.format(
              projectf,
              execs['povray'],
              #runlog,
              os.path.basename(infile), os.path.basename(outfile),
              os.path.basename(logfile), os.path.basename(inifile))
    status = os.system(cmd)
    success = os.path.exists(outfile)
    if not success:
        if not os.path.exists(logfile):
            """There were errors, but no log file.  Why?"""
        else:
            fileAppendText(runlog,"""THERE WERE ERRORS when Ambrosia attempted to render your image using POV.
            Below is the log of this rendering.
            You should look for hints on syntax errors near the phrase "Parsing", below.""")
            fileAppendFile(runlog,logfile)
            fileAppendText(runlog,"""No image was generated.""")
    if success:
        removeFiles(inifile,infile,logfile)
    return success

def pipCompose(model,gravity,runlog):
    smallfile = model+"-small.png"
    largefile = model+"-large.png"
    outfile = model+".png"

    status = os.system('cd "{}"; "{}" -gravity "{}" "{}" "{}" "{}" >>{} 2>/dev/null',
         os.path.dirname(model),
         execs['composite'],
         gravity,
         smallfile, largefile, outfile, runlog)
    return status == 0

def stereoCompose(model,runlog):
    leftfile = model+"-left.png"
    rightfile = model+"-right.png"
    outfile = model+".png"
    statusl = os.system('cd "{}"; "{}" -type Grayscale "{}" >>"{}" 2>/dev/null'.format(
            os.dirName(model),
            execs['mogrify'],
            leftfile,runlog))
    statusr = os.system('cd "{}"; "{}" -type Grayscale "{}" >>"{}" 2>/dev/null'.format(
            os.dirName(model),
            execs['mogrify'],
            rightfile,runlog))
    statuss = success and os.system('cd "{}"; "{}" -stereo "{}" "{}" "{}" >>"{}" 2>/dev/null'.format(
            os.dirName(model),
            execs['composite'],
            leftfile, rightfile,outfile,runlog))
    return success




def standardRender(model,runlog):
    success = povray(model,runlog)
    return success

def pipRender(model,gravity,runlog):
    success = povray(model+"-large",runlog)
    success = success and povray(model+"-small",runlog)
    success = success and pipCompose(model,gravity,runlog)
    if success:
        removeFiles(model+"-small.png",model+"-large.png")
    return success

def stereoRender(model,runlog):
    success = povray(model+"-left",runlog)
    success = success and povray(model+"-right",runlog)
    success = success and stereoCompose(model,runlog)
    if success:
        removeFiles(model+"-left.png",model+"-right.png")
    return success

def isometricRender(model, runlog):
    success = povray(model+"-right",runlog)
    success = success and povray(model+"-top",runlog)
    success = success and povray(model+"-front",runlog)
    success = success and povray(model+"-ortho",runlog)
    if success:
        removeFiles(model+'-right.png',model+'-top.png', model+'-front.png', model+'-ortho.png')
    return success

def fileAppendText(basefile,text):
    with open(basefile,'a') as bf:
        if isinstance(text,list):
            bf.writelines(text)
        else:
            bf.write(text)
        bf.close()

def fileAppendFile(basefile,extension):
    with open(basefile,'a') as bf:
        with open(extension) as ef:
            bf.writelines(ef.readlines())
            ef.close()
        bf.close()

def render(model,**kargs):
    debug = kargs.get('debug',False)
    keep = kargs.get('keep',False)
    batch = kargs.get('batch',False)
    projectf = os.path.dirname(model)
    runlog = model + ".runlog"
    result = model+".png"
    stereo = kargs.get('stereo',False)
    pip = kargs.get('pip',False)
    if 'gravity' in kargs:
        pip = True
        gravity = kargs['gravity']
    else:
        gravity = None
    isometric = kargs.get('isometric',False)
    if not os.path.exists(projectf):
        """Target directory for the output file does not exist"""
        return 1
    if pip:
        gravity = kargs.get('gravity','SouthEast')
        success = pipRender(model,runlog)
    elif stereo:
        success = stereoRender(model,runlog)
    elif isometric:
        success = isometricRender(model,runlog)
    else:
        success = standardRender(model,runlog)
    result = result if success else None
    return result
