#!/usr/bin/env python3

import argparse
import re
import os
import shutil
import sys
import subprocess
import time


'''
chooseviewer.py - choose a program for viewing a file, based either on the filename.extension, or
by an extension supplied on the command line. If --delete is set, delete the file after viewing.

The first arugment is a filename or URL. Usually, we can figure out
the type of file based on the file extension. However, if a second
argument is given, it is assumed to be a typical file extension
such as pdf, html, jpg etc. This is mainly for the case in which
a file doesn't have an extension, and we need to be able to tell
chooseviewer the type of file.

Synopsis: chooseviewer.py <filename> [--ext extension][--delete] [--wait] 

@modified: June 30, 2026
@author: Brian Fristensky
@contact: frist@cc.umanitoba.ca  
'''

PROGRAM = "chooseviewer.py : "
USAGE = "\n\tUSAGE: chooseviewer.py <filename> [--ext extension][--delete]"

DEBUG = True
if DEBUG :
    print('Debugging mode on')


# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Parameters:
    """
      	Wrapper class for command line parameters
      	"""
    def __init__(self):
        """
     	  Initializes arguments:
		Target = ""
                Ext = ""
                Delete = False
                Wait = False

     	  Then calls read_args() to fill in their values from command line
          """
        self.Target = sys.argv[1]
        self.Ext  = ""
        self.Delete  = False
        self.Wait = False 
        self.read_args()
        
        if DEBUG :
            print('------------ Parameters from command line ------')
            print('    Target: ' + self.Target)
            print('    Ext: ' + self.Ext)
            print('    Delete: ' + str(self.Delete))
            print('    Wait: ' + str(self.Wait))
            print()  

    def read_args(self):
        """
        	Read command line arguments into a Parameter object
    	"""	
        parser = argparse.ArgumentParser()
        parser.add_argument("infile", action="store", default="", help="input file")
        parser.add_argument("--ext", dest="ext", action="store", default="", help="file type")
        parser.add_argument("--delete", dest="delete", action="store_true", default=False, help="delete file after viewing")
        parser.add_argument("--wait", dest="wait", action="store_true", default=False, help="wait for viewer to terminate before terminating chooseviewer.py")
        args = parser.parse_args() 
        self.Target = args.infile
        self.Ext = args.ext
        self.Delete = args.delete
        self.Wait = args.wait

#---------------------------------------------------------------
# On macos, open no longer supports PostScript files. 
# We therefore have to convert PostScript to PDF
# However, this function could also be used for other
# platforms
def PStoPDF(FileName,Delete) :
    fn = FileName.rsplit('.')[0]
    ofn = fn + '.pdf'
    if os.environ.get("BIRCH_PLATFORM") in ["osx-x86_64","macos-arm64"] :
        COMMAND = ["pstopdf", FileName, "-o", ofn]
    else :
        COMMAND = ["ps2pdf", FileName, ofn]
    p = subprocess.Popen(COMMAND)
    p.wait()
    if Delete :
        os.remove(FileName)
    return ofn

#---------------------------------------------------------------
def LaunchViewer(FileName,Ext,Delete,Wait) :

    # Get rid of a leading period from a file extension. This means it doesn't
    # matter whether or not sys.argv[2]  begins with a dot.
    if Ext[0] == '.' :
        Ext = Ext[1:]

    # Some programs can't figure out how to open a file if it doesn't have the right file 
    # extension, so we make a duplicate file with a recognizable extension, and work with
    # that.
    if Ext != "Web" :
        Target = 'chooseviewer' + str(os.getpid()) + "." + Ext
        shutil.copy(FileName,Target)
    else:
        Target = FileName

    if DEBUG :
        print ("chooseviewer.py - Opening file: " + Target)

    #Most of these external calls have been switched over to subprocess, from birchscript.forkrun.
    # What seems to happen is that birchscript.forkrun runs in the background, allowing chooseviewer.py to 
    # terminate. This means that if the script that called chooseviewer deletes the input file as its
    # next step, that file will be deleted before the ace* scripts have time to make a copy. 
    # We probably also need a similar fix for web pages, but that would require a separate script
    # that opened a web browser.

    if Ext in ("Web", "html", "shtml", "htm"):
        # -------- Web pages
        Program = os.environ.get("BL_Browser")
        #Program = os.environ.get("BL_Browser") + " -new-instance"
            
    elif Ext == "pdf":
        # -------- PDF
        Program = os.environ.get("BL_PDFViewer")

    elif Ext in ("ps", "eps"):
        Target = PStoPDF(FileName,Delete)
        Program = os.environ.get("BL_PDFViewer")

    elif Ext in ("xls", "xlsx", "ods", "sxc", "csv", "tsv", "dif", "dbf","ctab"):
        # -------- Spreadsheet
        Program = os.environ.get("BL_Spreadsheet")

    elif Ext in ("odt", "sxw", "doc", "docx", "rtf"):
        # -------- Document
        Program = os.environ.get("BL_Document")

    elif Ext in ("gif", "jpg", "jpeg", "png", "bmp", "tif", "tiff"):
        # -------- Bitmap graphics
        Program = os.environ.get("BL_ImageViewer")

    else:
        # -------- Default is text editor
        Program = os.environ.get("BL_TextEditor")

    """    
    Treat the Program variable as a list of tokens 
    We do it this way to accommodate MacOSX, which launches 
    viewers using the open command.
    For example, to open a file using firefox

    open -a firefox filename

    """
    comstr = Program.split() #Break command into a list of tokens
    comstr.append(Target)

    if Wait :
        p = subprocess.Popen(comstr)
        p.wait()
        os.remove(Target)
    else:
        # I tried lots of permutations of subprocess, but was never able to get the
        # browser to open, and wait, and then delete the file, except by using os.system.
        #p = subprocess.Popen(comstr)
        #time.sleep(20)
        #os.remove(Target)
        COMMAND = '(' + Program + ' ' + Target + '; sleep 120; rm ' + Target + ')&'
        #p = subprocess.run(COMMAND, shell=True)
        os.system(COMMAND)
        

    # Remove the original, except if it is an external URL
    if (Delete and (not Ext == "Web")) :
        if DEBUG :
            print ('Deleting ' + FileName)
        time.sleep(5)
        os.remove(FileName)    

#======================== MAIN PROCEDURE ==========================

def chooseviewer():
    """
    	Called when not in documentation mode.
    	"""
    print ('Running chooseviewer.py')
    # Read parameters from command line
    P = Parameters()

    OKAY = True
    # If the Target is an external web page, we set Ext to Web. 
    # Launchviewer will not try to delete an external web page.
    if (re.search('^http:|^https:|^ftp:|^ftps:', P.Target)):
        P.Ext = "Web"

    # This is for files on the local filesystem.
    else :    
        if (os.path.isdir(P.Target)):
            OKAY = False
            print( "chooseviewer.py: cannot open directories!")
        elif (not os.path.exists(P.Target)):
            OKAY = False
            print ('chooseviewer.py: file not found')    

        if OKAY :
            if P.Ext == "" :
                P.Ext=os.path.splitext(P.Target)[1]
            P.Ext = P.Ext.lower()   
    if OKAY :
        if DEBUG :
            print('------------ Final Parameter Values ------')
            print('    Target: ' + P.Target)
            print('    Ext: ' + P.Ext)
            print('    Delete: ' + str(P.Delete)) 
            print('    Wait: ' + str(P.Wait)) 
        LaunchViewer(P.Target,P.Ext,P.Delete,P.Wait)
	
if __name__=="__main__":    
        chooseviewer()

