#!/usr/bin/env python

# ****************************************
# +++  BioCASE Provider Software v2
# +++  Installer script
# $Id: setup.py 1094 2011-08-17 10:20:23Z j.holetschek $
# ****************************************


import sys, os, string, shutil, exceptions
from types import *

 
class DevNull:
    '''/dev/null file object discarding all write data.'''
    def __init__(self):
        pass
    def write(self, x):
        pass
    
############################################################################################################
#
# FUNCTIONS
#
#===========================================================================================================
def askForParameter(question, boolean=False, selectList=None, default=None, isFile=False, isDir=False):
    '''Ask user for a parameter.'''
    answer = default
    if boolean:
        # only ask for yes or no
        defaultstr = ""
        if default is True: 
            defaultstr = " [yes]"
        elif default is False:
            default = False
            defaultstr = " [no]"
        answer = raw_input("%s%s " %(question, defaultstr))
        if answer is None or len(answer) == 0:
            answer = default
        while not answer in (True,False,"yes","y","no","n"):
            print " Please choose yes or no."
            answer = raw_input("%s%s " %(question, defaultstr))
            if answer is None or len(answer) == 0:
                answer = default
        if answer in ('yes','y',True):
            answer = True
        else:
            answer= False
    elif type(selectList) == ListType and len(selectList) > 0:
        i = 0
        selectDict = {}
        for option in selectList:
            selectDict[i] = option
            if default == option:
                default = i
            question += "\n  (%i) - %s" %(i,option)
        # ask question
        defaultstr = ""
        if default is not None:
            answer = raw_input("%s\nPlease select your option: [%s] " %(question, default))
            if answer is None or len(answer) == 0:
                answer = default
            while not selectDict.has_key(answer):
                print " Please select a valid option."
                answer = raw_input("%s\nPlease select your option: [%s] " %(question, default))
                if answer is None or len(answer) == 0:
                    answer = default
        else:
            answer = raw_input("%s\nPlease select your option: " %(question))
            while answer is None or not selectDict.has_key(answer):
                print " Please select a valid option."
                answer = raw_input("%s\nPlease select your option: " %(question))
        answer = selectDict[answer]
    else:
        defaultstr = ""
        if default is not None:
            answer = raw_input("%s [%s] " %(question, default))
            if answer is None or len(answer) == 0:
                answer = default
        else:
            answer = raw_input("%s " %(question))
            while answer is None or len(answer) == 0:
                print "Please enter something."
                answer = raw_input("%s " %(question))
        if isFile:
            # ensure its a file
            while not os.path.isfile(answer):
                print " The file does not exist. Please enter a valid filepath."
                answer = raw_input("%s%s " %(question, defaultstr))
        elif isDir:
            # ensure its a directory
            while not os.path.isdir(answer):
                print " The directory does not exist. Please enter a valid dirpath."
                answer = raw_input("%s%s " %(question, defaultstr))
    print " --> %s" % str(answer)
    return answer


def updateBpsPathCfg(bpsPath):
    fn=os.path.join(bpsPath,'lib','biocase','adjustpath.py')
    cfgF = file(fn, 'r')
    cfgF.readline() # discard previous first line
    text = "bpsPath = r'%s'\n"%bpsPath
    text += cfgF.read()
    cfgF.close()
    # write back
    fw = file(fn, 'w')
    fw.write(text)
    fw.close()

def copytree(src, dst, symlinks=False, removeSuffix=[]):
    """Recursively copy a directory tree using copy2().

    Modified version of the shutils function.
    Does not raise erros when dirs already exist.
    
    The destination directory must not already exist.
    If exception(s) occur, an Error is raised with a list of reasons.

    If the optional symlinks flag is true, symbolic links in the
    source tree result in symbolic links in the destination tree; if
    it is false, the contents of the files pointed to by symbolic
    links are copied.
    """
    names = os.listdir(src)
    if not os.path.isdir(dst):
        os.mkdir(dst)
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        if symlinks and os.path.islink(srcname):
            linkto = os.readlink(srcname)
            os.symlink(linkto, dstname)
        elif os.path.isdir(srcname):
            copytree(srcname, dstname, symlinks, removeSuffix)
        else:
            shutil.copyfile(srcname, dstname)
    # remove files which end as suffix XXX in destination
    for suffix in removeSuffix:
        names = os.listdir(dst)
        for name in names:
            if name.endswith(suffix):
                dstname = os.path.join(dst, name)
                try:
                    os.remove(dstname)
                except OSError:
                    print "Could not remove file %s"%dstname
        

def importConfiguration(ThisBpsPath):
    print "Importing existing configurations is currently not supported. Sorry."
    print "Please manually copy existing datasource files to this new installation."
    if askForParameter("Please press <return> to continue ?", boolean=True, default=True):
        pass
    return


############################################################################################################
#
# MAIN
#
#===========================================================================================================

if __name__ ==  "__main__":
    Interpreter         = sys.executable
    # adjust syspath for biocase lib
    bpsPath             = os.path.abspath('.')
    liblocator = os.path.join(bpsPath,'lib')
    sys.path.insert(0, liblocator)
    from biocase.configuration  import Cfg
    cfg = Cfg()
    # make sure we have loaded the right files. 
    # The hardcoded installation path in adjustpath.py is not necessarily right yet - we are about to configre this!
    cfg.reloadConfigFiles(bpsPath=bpsPath)
    # get this bps version
    from biocase import __version__ as Version
    # Intro text
    print '''
 +++  BioCASE Provider Software
 +++  Version %s
 +++  Installer script

 Configure BPS with:
 Python      %s
 BPS Library %s
 
This setup tool adapts the BioCASe Provider Software (BPS) to your system environment.'''%(Version,Interpreter, liblocator)
    
    # check for python version.
    if (sys.version[:3]< '2.5'):
        print '''Warning! This software was build for Python 2.5+
        Your current version %s of Python might not be supported, but you can try to run it anyways.
        ''' % string.split(sys.version, ' ')[0]
        if not askForParameter("Do you really want to install BPS with your existing python interpreter?", boolean=True, default=False):
            sys.exit()
    # update configuration.py libPath
    print "\n --> Updated absolute path to installation in configuration.py to %s"%bpsPath
    updateBpsPathCfg(bpsPath)
    # ask for upgrade
    #if askForParameter("\nThis script can import configurations from an existing BPS installation. Datasources, querytool skins and new custom templates will be copied, but modifications to default templates (querytool default skin) will be lost. This script will not modify your existing installation.\nDo you want to import configurations from an existing BPS installation ?", boolean=True, default=False):
    #    BpsImportPath = importConfiguration(bpsPath)
    #else:
    cfg.server.host    = askForParameter("Please indicate the domain of your webserver:", default='http://localhost')
    cfg.server.webroot = askForParameter("Please indicate the base URL you are planning to use for the software:", default='/biocase')        
    cfg.__save__()
    # run adapt2 tool
    os.chdir(os.path.join(bpsPath,'tools')) # change current working directory to adapt script
    print "Adapting file permissions and shebang lines to use python %s"%Interpreter
    execfile( os.path.join(bpsPath,'tools','fixpermissions.py' ))
    
    # FINISHED
    print "\n\n"
    print "#"*80
    print "Setup done."
    print "Please remember to setup Python CGIs on your webserver."
    print "If you use Apache, you can copy this snippet into your http.conf file:\n"
    BpsWwwPath = os.path.join(bpsPath, "www")
    print '''Alias   %s                        "%s"
<Directory                              "%s">
    AllowOverride                   None
    Order                           allow,deny
    Allow                           from all
    Options                         +ExecCGI +Indexes
    AddHandler                      cgi-script cgi
    AddHandler                      cgi-script py
    DirectoryIndex                  index.cgi index.py index.html
</Directory>''' % (cfg.server.webroot, BpsWwwPath, BpsWwwPath)
    print "\nPlease test your installation at %s" %cfg.getWebappURL()
        
