import os
import sys
import argparse
import json

"""
Installation script to build Utsusemi on AlmaLinux 8, 9 and Ubuntu 22, 24

2025/7/2 1.0RC

$ ls src
LASTUPDATED  manyo/  uGao/  Utsusemi/  Utsusemi-DNA/  Utsusemi-ENG/  Utsusemi-SAS/
$ python3 Install.py
"""

DICT_BLCODE = {"1":"SIK", "2":"DNA", "10":"NBR", "11":"HPN", "14":"AMR", "15":"SAS", "17":"VNR", "19":"ENG"}

SOURCE_ALL_LIST = ["manyo", "Utsusemi", "Utsusemi-SAS", "Utsusemi-DNA", "Utsusemi-ENG"]
ALL_BL_LIST = ["SIK", "AMR", "HPN", "SAS", "DNA", "ENG", "VNR"]
DIC_WITHPARA = {"Y":"USE", "N":"NOT USE"}

DEF_SETTINGS_FILE = "utsusemi_installation_setting.json"

# keys of parameter dictionary
KEY_MLFSOFT_PATH = "mlfsoft_path"
KEY_DATA_DIR = "data_dir"
KEY_USER_DIR = "user_dir"
KEY_INSTTYPE = "manyo_insttype"
KEY_NUMTH = "numth"
KEY_REV = "rev"
KEY_WITHPARA = "with_para"
KEY_DISTRIBUTION = "distribution"
KEY_INSTALLATION_PATH = "installation_path"
KEY_ROOTPATH = "root_path"
KEY_SETTINGS_FILE = "settings_file"

# distribution definitions
KEY_DIST_RH8 = "RH8"
KEY_DIST_RH9 = "RH9"
KEY_DIST_UBU22 = "Ubuntu22"
KEY_DIST_UBU24 = "Ubuntu24"

def checkOS():
    """Check the distribution

    Args:
    Returns:
        str: name of distribution "RH8", "RH9", "Ubuntu"

    """
    if os.path.exists("/etc/redhat-release"):
        with open("/etc/redhat-release", "r") as f:
            r = f.readline()
            r_list = r.split(" ")
            for i, rel in enumerate(r_list):
                if rel == "release":
                    p = r_list[i + 1]
                    break
            if p.find("8") == 0:
                return KEY_DIST_RH8
            elif p.find("9") == 0:
                return KEY_DIST_RH9
    elif os.path.exists("/etc/issue"):
        with open("/etc/issue", "r") as f:
            t = f.readline()
            v = t.split(' ')
            if v[0] == "Ubuntu":
                if v[1].find("24.04") == 0:
                    return KEY_DIST_UBU24
                elif v[1].find("22.04") == 0:
                    return KEY_DIST_UBU22
            elif v[0] == "Linux" and v[1] == "Mint":
                ver_list = v[2].split(".")
                if int(ver_list[0]) == 22:
                    return KEY_DIST_UBU24
                elif int(ver_list[0]) == 21:
                    return KEY_DIST_UBU22

    print("ERROR OS is invalid. Avairable OS : RH(AlamaLinux, RockyLinux) 8/9 and UbuntuLinux 24.04/22.04 (Mint linux 22/21)")
    return ""

def parseArgs(param_dic):
    '''Parse argument of this script file

    Args:
        param_dic (dic): Dictionary to store parameters
    Returns:

    '''
    parser = argparse.ArgumentParser(description="The script to install Manyo/Utsusemi")
    parser.add_argument('--mlfsoft-path', help='set MLFSOFT_PATH')
    parser.add_argument('--manyo-insttype', help='set manyo-lib installation type "O"ld or "N"ew', default="O")
    parser.add_argument('--numth', type=int, help='set the number of multi-threading', default=2)
    parser.add_argument('--rev', help='revision number default:YYYYMMDD')
    parser.add_argument('--with-para', action='store_true', help='make with option -j')
    parser.add_argument('--without-para', action='store_true', help='make without option -j')
    args = parser.parse_args()

    if os.path.exists(DEF_SETTINGS_FILE):
        with open(DEF_SETTINGS_FILE, "r") as f:
            try:
                pre_params = json.load(f)
            except:
                pre_params = {}
            for akey in pre_params:
                param_dic[akey] = pre_params[akey]

    if len(param_dic) != 10:
        param_dic[KEY_MLFSOFT_PATH] = ""
        param_dic[KEY_INSTTYPE] = "O"
        param_dic[KEY_NUMTH] = 2
        param_dic[KEY_REV] = ""
        param_dic[KEY_WITHPARA] = "N"
        param_dic[KEY_DISTRIBUTION] = ""
        param_dic[KEY_ROOTPATH] = os.path.dirname(__file__)
        param_dic[KEY_USER_DIR] = os.path.join(os.environ["HOME"], "utsusemi")
        param_dic[KEY_DATA_DIR] = os.path.join(os.environ["HOME"], "mlfsoft", "data")
        param_dic[KEY_SETTINGS_FILE] = DEF_SETTINGS_FILE

    param_dic[KEY_MLFSOFT_PATH] = os.path.join(os.environ["HOME"], "mlfsoft")
    if args.mlfsoft_path is not None:
        param_dic[KEY_MLFSOFT_PATH] = args.mlfsoft_path
    param_dic[KEY_INSTTYPE] = "O"
    if args.manyo_insttype is not None:
        param_dic[KEY_INSTTYPE] = args.manyo_insttype
    param_dic[KEY_NUMTH] = 2
    if args.numth is not None:
        param_dic[KEY_NUMTH] = args.numth
    param_dic[KEY_REV] = ""
    if args.rev is not None:
        param_dic[KEY_REV] = args.rev
    param_dic[KEY_WITHPARA] = "N"
    if args.with_para and (not args.without_para):
        param_dic[KEY_WITHPARA] = "Y"
    param_dic[KEY_DISTRIBUTION] = checkOS()
    print("#[inamura 260717] CheckOS = {}".format(checkOS()))

def installCppPackages(params):
    """installation of packages for C++ libraries required by Manyo/Utsusemi

    Args:
        params (dictionary): Dictionary including some parameters produced by parseArgs()
    Returns:
        bool: True means succeeded.
    """
    com_list = []
    target_os = params[KEY_DISTRIBUTION]
    if target_os == KEY_DIST_RH8:
        #com_list.append('sudo yum groupinstall base "Development tools" --setopt=group_package_types=mandatory,default,optional')
        #com_list.append("sudo yum install epel-release")
        com_list.append("sudo dnf install -y swig cmake git")
        com_list.append("sudo dnf install -y mxml-devel hdf5-devel gsl-devel boost-devel openssl-devel")
        com_list.append("sudo dnf install -y blas-devel lapack-devel")
        com_list.append("sudo dnf install -y python39-devel")
        com_list.append("sudo dnf install -y python39-pip")
        com_list.append("sudo alternatives --set python3 /usr/bin/python3.9")
    elif target_os == KEY_DIST_RH9:
        com_list.append("sudo dnf install -y swig cmake git")
        com_list.append("sudo dnf install -y mxml-devel hdf5-devel gsl-devel boost-devel openssl-devel")
        com_list.append("sudo dnf install -y blas-devel lapack-devel")
        com_list.append("sudo dnf install -y python3.11-devel")
        com_list.append("sudo dnf install -y python3.11-pip")
        com_list.append("sudo alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 30")
        com_list.append("sudo alternatives --set python3 /usr/bin/python3.11")
        # com_list.append("sudo alternatives --set python3 /usr/bin/python3")
    elif target_os == KEY_DIST_UBU22 or target_os == KEY_DIST_UBU24:
        com_list.append("sudo apt-get install -y g++ swig make cmake")
        com_list.append("sudo apt-get install -y python3-dev")
        com_list.append("sudo apt-get install -y libhdf5-dev libmxml-dev libgsl-dev libssl-dev liblapack-dev")
        com_list.append('sudo apt-get install -y libnexus-dev')
        #com_list.append('sudo apt-get install -y libboost-dev')
        com_list.append('sudo apt-get install -y libboost-serialization-dev')
        com_list.append('sudo apt-get install -y libboost-filesystem-dev')
        com_list.append('sudo apt-get install -y libboost-system-dev')
        com_list.append('sudo apt-get install -y libboost-program-options-dev')
        com_list.append('sudo apt-get install -y zlib1g-dev')
        com_list.append('sudo apt-get install -y python3-pip')
        com_list.append('sudo apt-get install -y libxcb-cursor0')
    else:
        print("ERROR : Invalid os, which should be RH8/RH9/Ubuntu24/Ubuntu22/Mint22/Mint21")
        return False
    print("\n ==============================\n")
    for a_com in com_list:
        print("COMMAND : {}".format(a_com))
        if os.system(a_com) != 0:
            print("## ERROR : command = {}".format(a_com))
            return False
        else:
            pass

    if target_os == KEY_DIST_RH8 or target_os == KEY_DIST_RH9:
        if params[KEY_INSTTYPE] == "O":
            com_list = commandsBuildNexusformat(os.path.join(params[KEY_MLFSOFT_PATH], "manyo"))
        else:
            com_list = commandsBuildNexusformat(params[KEY_MLFSOFT_PATH])
        for a_com in com_list:
            print("COMMAND : {}".format(a_com))
            if os.system(a_com) != 0:
                print("## ERROR : command = {}".format(a_com))
                return False
            else:
                pass
    return True

def commandsBuildNexusformat(install_path):
    '''Make the installation proceedure of nexusformat from codes

    Args:
        install_path (str): The path to install nexusformat
    Returns:
        list: list of commands to install nexusformat

    '''
    com = []
    if not os.path.exists(os.path.join(os.getcwd(), "src", "code")):
        com.append("cd src;git clone https://github.com/nexusformat/code")
    else:
        com.append("rm -rf src/code/build")
    com.append("mkdir -p src/code/build")
    com.append("cd src/code/build;rm -rf *; cmake -DCMAKE_INSTALL_PREFIX={} ..".format(install_path))
    com.append("cd src/code/build; make; make install")
    com.append("mkdir -p {}".format(os.path.join(install_path, "lib")))
    com.append("cp {}/lib* {}".format(os.path.join(install_path, "lib64"), os.path.join(install_path, "lib")))
    return com

def commandsCMake(source_path, params):
    '''Make the build procedure of C++(Manyo) codes using CMake

    Args:
        source_path (str): Path to source codes folder
    Returns:
        list:  list of commands to build C++ codes using CMake
    '''
    install_path = params[KEY_MLFSOFT_PATH]
    numth = int(params[KEY_NUMTH])
    insttype = params[KEY_INSTTYPE]
    if insttype =="O":
        # install_path = os.path.join(install_path, "manyo")
        install_path = install_path
    elif insttype == "N":
        install_path = os.path.join(install_path, "utsusemi")

    utsusemi_rev = "0"
    print(" #################### Utsusemi LASTUPDATED = {}".format(os.path.join(os.path.join(params[KEY_ROOTPATH], "src", "LASTUPDATED"))))
    if os.path.exists(os.path.join(os.path.join(params[KEY_ROOTPATH], "src", "LASTUPDATED"))):
        with open(os.path.join(os.path.join(params[KEY_ROOTPATH], "src", "LASTUPDATED")), "r") as f0:
            utsusemi_rev = f0.readline().strip()
    print(" #################### Utsusemi revision = {}".format(utsusemi_rev))
    com = []
    build_path = os.path.join(source_path, "build")
    com.append("mkdir -p {}".format(build_path))
    com_cmake = "cd {};rm -rf *; cmake .. -DCMAKE_INSTALL_PREFIX={} -DMULTH={} -DMANYO_INSTTYPE={} -DUTSUSEMI_REV={}".format(build_path, install_path, numth, insttype, utsusemi_rev)
    if params[KEY_DISTRIBUTION] == KEY_DIST_RH8:
        com_cmake += ' -DPython_EXECUTABLE="/usr/bin/python3.9"'
    com.append(com_cmake)

    if params[KEY_WITHPARA] == "Y":
        com.append("cd {}; make -j install".format(build_path))
    else:
        com.append("cd {}; make install".format(build_path))

    params[KEY_INSTALLATION_PATH] = install_path
    return com

def execute(coms, outlist, errlist):
    '''Execute commands procedure given as str list.

    Args:
        coms (list): str list for commands
        outlist (list): list to store executed commands
        errlist (list): list to store error message by executing command
    returns:

    '''
    for acom in coms:
        print("EXECUTE : {}".format(acom))
        if os.system(acom) != 0:
            outlist.append(acom)
            errlist.append("ERROR on executing {}".format(acom))
            print("{} is failed.".format(acom))
            return False
        else:
            outlist.append(acom)
            errlist.append("")
    return True

def commandsPythonPackages():
    '''Make command procedure to install python packages using pip

    Args:
    Returns:
        list: list of commands
    '''
    coms = []
    target_os = params[KEY_DISTRIBUTION]
    if target_os == KEY_DIST_RH8:
        coms.append("python3 -m pip install numpy scipy matplotlib PySide2")
    elif target_os != KEY_DIST_UBU24:
        coms.append("python3 -m pip install numpy scipy matplotlib PySide6")
    return coms

def getLibraryInstallationPath(params):
    """Get the path of the folder of the installed libraries

    Args:
        params (dict) : parameters dictionary
    Returns:
        str: path to the installed librarirs folder
    """
    insttype = params[KEY_INSTTYPE]
    if insttype == "O":
        lib_path = os.path.join(params[KEY_MLFSOFT_PATH], "manyo", "lib")
    elif insttype == "N":
        py_ver = "python{}.{}".format(sys.version_info.major, sys.version_info.minor)
        if checkOS().find("Ubuntu") == 0:
            pack_path = "dist-packages"
        else:
            pack_path = "site-packages"
        lib_path = os.path.join(params[KEY_MLFSOFT_PATH], "lib", py_ver, pack_path)
    else:
        print("ERROR : insttype is invalid {}".format(insttype))
        return None
    return lib_path

def commandsPythonUtsusemi(source_path, params, target_bl=[]):
    '''Make command procedure to install python codes for Utsusemi

    Args:
        source_path (str): Path to source codes folder
        params (dic): Parameters dictionary
        target_bl (list): list of BL to install
    Returns:
        list: list of commands
    '''
    insttype = params[KEY_INSTTYPE]
    if insttype == "O":
        install_path = os.path.join(params[KEY_MLFSOFT_PATH], "python-utsusemi", "utsusemi")
    elif insttype == "N":
        py_ver = "python{}.{}".format(sys.version_info.major, sys.version_info.minor)
        if checkOS().find("Ubuntu") == 0:
            pack_path = "dist-packages"
        else:
            pack_path = "site-packages"
        install_path = os.path.join(params[KEY_MLFSOFT_PATH], "lib", py_ver, pack_path, "utsusemi")
    else:
        print("ERROR : insttype is invalid {}".format(insttype))
        return []

    # Utsusemi Base codes
    com = []
    com.append("mkdir -p {}".format(install_path))
    for sfolder in ["ana", "bin", "facade", "vis"]:
        com.append("cp -r {} {}".format(os.path.join(source_path, "Utsusemi", "python-utsusemi", sfolder), os.path.join(install_path)))
    com.append("cp {} {}".format(os.path.join(source_path, "Utsusemi", "python-utsusemi", "__init__.py"), os.path.join(install_path)))
    com.append("mkdir -p {}".format(os.path.join(params[KEY_USER_DIR], "ana", "tmp")))
    com.append("mkdir -p {}".format(os.path.join(params[KEY_USER_DIR], "ana", "xml")))

    # uGao
    com.append("cp -r {} {}".format(os.path.join(source_path, "uGao"), os.path.dirname(install_path)))

    # BL codes
    for a_bl in target_bl:
        print("commandsPythonUtsusemi target_bl = '{}'".format(a_bl))
        if a_bl in ["AMR", "HPN", "SIK", "VNR"]:
            print("Add {}".format(a_bl))
            com.append("cp -r {} {}".format(os.path.join(source_path, "Utsusemi", "python-utsusemi-{}".format(a_bl)), os.path.join(install_path, a_bl)))
        elif a_bl == "SAS":
            com.append("cp -r {} {}".format(os.path.join(source_path, "Utsusemi-SAS", "python-utsusemi-SAS"), os.path.join(install_path, "SAS")))
            com.append("cp {} {}".format(os.path.join(source_path, "Utsusemi-SAS", "python-utsusemi-SAS", "bin", "*"), os.path.join(install_path, "bin")))
        elif a_bl == "DNA":
            com.append("cp -r {} {}".format(os.path.join(source_path, "Utsusemi-DNA", "python-utsusemi-DNA"), os.path.join(install_path, "DNA")))
            com.append("cp -r {} {}".format(os.path.join(source_path, "Utsusemi-DNA", "environ-home"), os.path.join(params[KEY_USER_DIR], "ana", "DNA")))
        elif a_bl == "ENG":
            com.append("cp -r {} {}".format(os.path.join(source_path, "Utsusemi-ENG", "python-utsusemi-ENG"), os.path.join(install_path, "ENG")))
        else:
            print("ERROR : given BL {} is invalid.".format(a_bl))
            return None
    return com

def commandsMakeSetting(params):
    """Create commands to make setting to launch Utsusemi

    Args:
        params (dic): Parameters dictionary
    Returns:
        list: commands
    """
    com = []
    bashrc_path = os.path.join(params[KEY_MLFSOFT_PATH], "bashrc_utsusemi")
    title = "# Utsusemi environment setting\n"
    com.append("echo '{}' > {}".format(title, bashrc_path))
    setting1 = "export MLFSOFT_PATH={}\n".format(params[KEY_MLFSOFT_PATH])
    com.append("echo '{}' >> {}".format(setting1, bashrc_path))
    setting2 = "export PATH=${{MLFSOFT_PATH}}/{}:${{PATH}}\n".format(os.path.join("python-utsusemi", "utsusemi", "bin"))
    com.append("echo '{}' >> {}".format(setting2, bashrc_path))
    return com

def createUtsusemiEnvCfg(params, inst="SIK"):
    """
    """
    utsusemi_config = """
UTSUSEMI_INST_CODE={}
UTSUSEMI_LOG_QUIET=Y
UTSUSEMI_DEBUGMODE=N
UTSUSEMI_MULTH={}
UTSUSEMI_DATA_DIR="/home/yinamura/data"
UTSUSEMI_USR_DIR={}
UTSUSEMI_WORK_DIR={}
UTSUSEMI_DEFAULT_FONTSIZE=12
""".format(inst, params[KEY_NUMTH], params[KEY_USER_DIR], params[KEY_USER_DIR])
    # Utsusemi Environment
    # "utsusemienv.cfg"
    utsusemienv_cfg_dir = os.path.join(os.environ["HOME"], ".mlfsoft", "utsusemi")
    utsusemienv_cfg_path = os.path.join(utsusemienv_cfg_dir, "utsusemienv.cfg")
    com = "mkdir -p {}".format(utsusemienv_cfg_dir)
    if os.system(com) != 0:
        return False
    with open(utsusemienv_cfg_path, "w") as f:
        f.write(utsusemi_config)
    return True

def commandsDeleteAll(params):
    """Create commands to delete all

    Args:
        params (dic): Parameters dictionary
    Returns:
        list: commands
    """
    com = []
    if params[KEY_INSTTYPE] == "O":
        com.append("sudo rm -rf {}".format(os.path.join(params[KEY_MLFSOFT_PATH], "manyo")))
        com.append("sudo rm -rf {}".format(os.path.join(params[KEY_MLFSOFT_PATH], "python-utsusemi")))
    else:
        com.append("sudo rm -rf {}".format(os.path.join(params[KEY_MLFSOFT_PATH], "utsusemi")))
    return com


def MainMenu(params, outlist=[], errlist=[]):
    """Show the main menu

    Args:
        params (dic): Parameters dictionary
        outlist (list): executed commands
        errlist (list): occured errors
    Returns:
        bool: result for executing commands
    """
    menu_str = """
==================================================
     Welcome to Utsusemi software installer
==================================================
 Installation Directories
    MLF software root   : {}
    RAW data Directory  : {}
    User's directory    : {}
----------------------------------------------------------
Main menu :
1 .. Install ALL modules (all beamlines)
--------
2 .. Install Manyo Library and Utsusemi codes
3 .. Add Beamline environment

5 .. Change Installation Directories
7 .. Uninstall
0 or 9 .. Exit
----------------------------------------------------------
"""
    menu_str = """
==================================================
     Welcome to Utsusemi software installer
==================================================
 Installation Parameters
    MLF software root   : {}
    User's directory    : {}
    Number of threads   : {}
    Build with the parallel processing : {}

----------------------------------------------------------
Main menu :
1 .. Install ALL modules (all beamlines)
--------
2 .. Install Manyo Library and Utsusemi codes
3 .. Add Beamline Environment

5 .. Change Installation Parameters
7 .. Uninstall
0 or 9 .. Exit
----------------------------------------------------------
"""

    while(True):
        #print(menu_str.format(params[KEY_MLFSOFT_PATH], params[KEY_DATA_DIR], params[KEY_USER_DIR]))
        print(menu_str.format(params[KEY_MLFSOFT_PATH], params[KEY_USER_DIR], params[KEY_NUMTH], DIC_WITHPARA[params[KEY_WITHPARA]]))
        ret = input(">> Which ? ")
        if ret not in ["0", "1", "2", "3", "5", "7", "9"]:
            print("Exit without installation.")
            return False
        try:
            no = int(ret)
        except:
            print("Exit without installation.")
            return False
        result = False
        if no == 1:
            result = menu_1(params, outlist, errlist)
        elif no == 2:
            if inputMULTH(params):
                result = menu_2(params, ["manyo", "Utsusemi"], outlist, errlist)
        elif no == 3:
            result = menu_3(params, [], outlist, errlist)
        elif no == 5:
            result = menu_5(params)
        elif no == 7:
            ret = input(">>> All delete OK ? (N/yes): ")
            ret = ret.strip().upper()
            if ret == "YES":
                coms = commandsDeleteAll(params)
                if not execute(coms, outlist, errlist):
                    return False
        elif (not result) or no == 0 or no == 9:
            break
        with open(DEF_SETTINGS_FILE, "w") as f:
            json.dump(params, f)

        ret = input(">> Back to Main Menu? [Y/n]")
        if ret.strip().upper() == "N":
            break
    return True


def inputMULTH(params):
    """Input number of multi-threads

    Args:
        params (dic): Parameters dictionary
    Returns:
        bool: result for executing commands
    """
    ret = input(">>> How many threads for multi-treading data treatment (>=1, Default={}) :".format(params[KEY_NUMTH]))
    if ret == "":
        pass
    else:
        try:
            params[KEY_NUMTH] = int(ret)
        except:
            print("ERROR : input is invalid.")
            return False
    return True

def menu_1(params, outlist=[], errlist=[]):
    """Installation All

    Args:
        params (dic): Parameters dictionary
        outlist (list): executed commands
        errlist (list): occured errors
    Returns:
        bool: result for executing commands
    """
    if inputMULTH(params):
        if menu_2(params, SOURCE_ALL_LIST, outlist, errlist):
            if menu_3(params, ALL_BL_LIST, outlist, errlist):
                print("--------------------------------------------")
                print("Utsusemi Default Installations is completed.")
                print("--------------------------------------------")
                return True
    return False


def menu_2(params, target_list, outlist=[], errlist=[]):
    """Do Install Manyo Library and Utsusemi codes

    Args:
        params (dic): Parameters dictionary
        target_list (list): Build targets
        outlist (list): executed commands
        errlist (list): occured errors
    Returns:
        bool: result for executing commands
    """
    isCppPackInstalled = False
    if os.path.exists(os.path.join(getLibraryInstallationPath(params), "libUtsusemi.so")):
        isCppPackInstalled = True
    else:
        isCppPackInstalled = installCppPackages(params)

    if isCppPackInstalled:
        print("######### Cpp Packageses installation is succeeded.")
        for a_target in target_list:
            source_path = os.path.join(params[KEY_ROOTPATH], "src", a_target)
            if a_target in SOURCE_ALL_LIST:
                coms = commandsCMake(source_path, params)
            else:
                print("WARNING : Target dir = {} is not found.".format(a_target))
                print("          Available target Dir = ", SOURCE_ALL_LIST)
                return False
            for a_com in coms:
                print("com = {}".format(a_com))
            if not execute(coms, outlist, errlist):
                return False

        print("\nManyo Library and Utsusemi codes installation is completed.")
        print("-----------------------------------------------------------")
        return True
    else:
        return False

def menu_3(params, target_list=[], outlist=[], errlist=[]):
    """Add Beamline environment

    Args:
        params (dic): Parameters dictionary
        target_list (list): Targets to be installed
        outlist (list): executed commands
        errlist (list): occured errors
    Returns:
        bool: result for executing commands
    """
    # if never done menu #2, return False.
    if not os.path.exists(os.path.join(getLibraryInstallationPath(params), "libUtsusemi.so")):
        print("Menu #2 (Install Manyo Library and Utsusemi base codes) has never been executed.")
        print("You must do menu #2 befor doing menu #3.")
        return False

    menu2_str = """
---------------------------------
  Select Beam Lines you install
---------------------------------
 [ 1] BL01 4SEASONS (SIK)
 [ 2] BL02 DNA (DNA)
 [11] BL11 PLANET (HPN)
 [14] BL14 AMATERAS (AMR)
 [15] BL15 Taikan (SAS)
 [17] BL17 Sharaku (VNR)
 [19] BL19 Takumi (ENG)
----------------
 [ 0] Exit menu
---------------------------------
"""
    if len(target_list) == 0:
        print(menu2_str)
        ret = input(">>> Which Packages (N[, M, L]): ")
        for a_bl in ret.split(","):
            if a_bl.strip() == "0":
                target_list = []
                break
            if a_bl in DICT_BLCODE:
                target_list.append(DICT_BLCODE[a_bl.strip()])
    if len(target_list) == 0:
        return False

    result = True
    installed_list = ""
    for a_bl in target_list:
        if a_bl == "SAS":
            if not os.path.exists(os.path.join(getLibraryInstallationPath(params), "libSAS.so")):
                if inputMULTH(params):
                    result = menu_2(params, ["Utsusemi-SAS"], outlist, errlist)
        elif a_bl == "DNA":
            if not os.path.exists(os.path.join(getLibraryInstallationPath(params), "libDNA.so")):
                if inputMULTH(params):
                    result = menu_2(params, ["Utsusemi-DNA"], outlist, errlist)
        elif a_bl == "ENG":
            if not os.path.exists(os.path.join(getLibraryInstallationPath(params), "libEmaki.so")):
                if inputMULTH(params):
                    result = menu_2(params, ["Utsusemi-ENG"], outlist, errlist)
        installed_list += (a_bl + ",")

    if not result:
        return False

    coms = commandsPythonPackages()
    if not execute(coms, outlist, errlist):
        return False

    source_path = os.path.join(params[KEY_ROOTPATH], "src")
    coms = commandsPythonUtsusemi(source_path, params, target_list)
    if len(coms) != 0:
        if not execute(coms, outlist, errlist):
            return False

    coms = commandsMakeSetting(params)
    if len(coms) != 0:
        if not execute(coms, outlist, errlist):
            return False

    if createUtsusemiEnvCfg(params, target_list[0]):
        pass
    else:
        print("# ERROR : Failed to write utsusemienv.cnf")
        return False

    print("\nAddition of {} environments is completed.".format(installed_list[:-1]))
    print("-----------------------------------------------------------")
    return True


def menu_5(params):
    """Change Installation parameters

    Args:
        params (dic): Parameters dictionary
    Returns:
        bool: result for executing commands
    """
    menu5_str = """
Change Installation Directories
--------------------------------------
1 .. MLF software root   : {}
2 .. RAW data Directory  : {}
3 .. User's directory    : {}
0 .. Return to main menu
"""
    menu5_str = """
Change Installation Parameters
--------------------------------------
1 .. MLF software root   : {}
2 .. User's directory    : {}
3 .. Number of threads   : {}
4 .. Build with the parallel processing : {}
0 .. Return to main menu
"""
    ans = -1
    while(ans != 0):
        # print(menu5_str.format(params[KEY_MLFSOFT_PATH], params[KEY_DATA_DIR], params[KEY_USER_DIR]))
        print(menu5_str.format(params[KEY_MLFSOFT_PATH], params[KEY_USER_DIR], params[KEY_NUMTH], DIC_WITHPARA[params[KEY_WITHPARA]]))
        ret = input(">>> Which change: ")
        try:
            ans = int(ret)
        except:
            ans = 0
        if ans == 1:
            ret = input(">>> new MLF software root: ")
            if ret != "":
                params[KEY_MLFSOFT_PATH] = ret.strip()
        elif ans == 2:
            ret = input(">>> new users dir: ")
            if ret != "":
                params[KEY_USER_DIR] = ret.strip()
        elif ans == 3:
            ret = input(">>> new number of threads: ")
            if ret != "":
                try:
                    params[KEY_NUMTH] = int(ret.strip())
                except:
                    print("Invalid Number.")
        elif ans == 4:
            ret = input(">>> Parallel processing [y/n]: ")
            ret = ret.strip().upper()
            if ret == "Y":
                params[KEY_WITHPARA] = "Y"
            else:
                params[KEY_WITHPARA] = "N"

        """
        elif ans == 2:
            ret = input(">>> new RAW data dir: ")
            if ret != "":
                params[KEY_DATA_DIR] = ret.strip()
        else:
            pass
        """
    return True

if __name__ == '__main__':
    params = {}
    parseArgs(params)
    outlist = []
    errlist = []

    if MainMenu(params, outlist, errlist):
        print("Finished.")
        # print(outlist)
    else:
        print("ERROR occurs.")
        # print(errlist)
