#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2016 Pi-Yueh Chuang <pychuang@gwu.edu>
#
# Distributed under terms of the MIT license.

"""convert the output file in a batch"""

import os
import os.path as op
import sys
import argparse

if os.getenv("PyFR") is None:
    raise EnvironmentError("Environmental variable PyFR is not set")
else:
    PyFRPath = os.getenv("PyFR")

    if PyFRPath not in sys.path:
        sys.path.append(PyFRPath)

try:
    import pyfr
    import pyfr.writers
except ImportError as err:
    err.msg += "! Please check the path set in the environmental variable PyFR."
    raise


def parseArgs(args=sys.argv[1:]):
    """parse arguments

    Args:
        args: list of strings. Default is sys.argv[1:].

    Returns:
        parser.parse_args(args)
    """

    parser = argparse.ArgumentParser(
        description="2D Cavity Flow Post-Precessor")

    parser.add_argument(
        "casePath", metavar="path",
        help="The path to a PyFR case folder", type=str)

    parser.add_argument(
        "-s", "--soln-dir", metavar="soln-dir", dest="solnDir",
        help="The directory (under casePath) containing *.pyfrs files. " +
        "(Default = solutions)",
        type=str, default="solutions")

    parser.add_argument(
        "-v", "--vtu-dir", metavar="vtu-dir", dest="vtuDir",
        help="The directory (under casePath) in where *.vtu files will be. " +
        "If the folder does not exist, the script will create it. "
        "(Default = vtu)",
        type=str, default="vtu")

    parser.add_argument(
        "-m", "--mesh", metavar="mesh", dest="mesh",
        help="The mesh file required. " +
        "The default is to use the first-found .pyfrm file in the case " +
        "directory. If multiple .pyfrm files exist in the case directory, "
        "it is suggested to set the argument.",
        type=str, default=None)

    parser.add_argument(
        "-o", "--overwrite", dest="overwrite",
        help="Whether to overwrite the output files if they already exist.",
        action="store_true")

    parser.add_argument(
        "-d", "--degree", dest="degree",
        help="The level of mesh. If the solver use higher-order " +
        "polynomials, than it may be necessary to set larger degree.",
        type=int, default=0)

    return parser.parse_args(args)


def setup_dirs(args):
    """set up path to directories necessary

    Args:
        args: parsed arguments generated by parser.parse_args()

    Returns:
        areparse.Namespace object with full paths
    """

    # set up the path to case directory
    args.casePath = os.path.abspath(args.casePath)

    # set up and check the path to case directory
    args.solnDir = args.casePath + "/" + args.solnDir
    if not op.isdir(args.solnDir):
        raise RuntimeError(
            "The path " + args.solnDir + " does not exist.")

    # set up the path for .pyfrm file
    if args.mesh is not None:
        args.mesh = args.casePath + "/" + args.mesh
        if not op.isfile(args.mesh):
            raise RuntimeError(
                "The input mesh file " + args.mesh + " does not exist.")
    else:
        for f in os.listdir(args.casePath):
            if f.endswith(".pyfrm"):
                args.mesh = args.casePath + "/" + f
        if args.mesh is None:
            raise RuntimeError(
                "Could not find any .pyfrm file in the case folder " +
                args.casePath)

    # set up and create the directory for .vtu files, if it does not exist
    args.vtuDir = args.casePath + "/" + args.vtuDir
    if not op.isdir(args.vtuDir):
        os.mkdir(args.vtuDir)

    return args


def get_pyfrs_list(pyfrsDirPath):
    """get list of file names that end with .pyfrs in pyfrsDirPath

    Args:
        pyfrsDirPath: path to the folder of .pyfrs files

    Returns:
        a list of file names
    """

    fileList = [f for f in os.listdir(pyfrsDirPath)
                if op.splitext(f)[1] == ".pyfrs"]

    if len(fileList) == 0:
        raise RuntimeError(
            "No .pyfrs file was found in the path " + pyfrsDirPath)

    return fileList


def generate_vtu(vtuPath, pyfrsPath, pyfrsList, mesh, overwrite, degree):
    """generate .vtu files, if they do not exist

    Args:
        vtuPath: the path to folder of .vtu files
        pyfrsPath: the path to .pyfrs files
        pyfrsList: the list of .pyfrs which to be converted
        mesh: the .pyfrm file
        overwrite: whether to overwrite the .vtu file if it already exist
    """

    vtuList = [op.splitext(f)[0]+".vtu" for f in pyfrsList]

    for i, o in zip(pyfrsList, vtuList):
        ifile = op.join(pyfrsPath, i)
        ofile = op.join(vtuPath, o)
        if op.isfile(ofile) and not overwrite:
            print("Warning: " +
                  "the vtu file " + o + " exists " +
                  "and won't be overwrited because overwrite=False")
        else:
            output_vtu(mesh, ifile, ofile, degree)


def output_vtu(mesh, iFile, oFile, g=True, p="double", d=0):
    """convert a single .pyfrs file to .vtu file using PyFR's converter

    Args:
        mesh: mesh file (must end with .pyfrm)
        input: input file name (must end with .pyfrs)
        output: output file name (must end with .vtu)
        g: whether to export gradients
        p: precision, either "single" or "double"
        d: degree of the element (set this according the order of the polynimal)
    """

    writerArgs = argparse.Namespace(
        meshf=mesh, solnf=iFile, outf=oFile, precision=p,
        gradients=g, divisor=d)

    writer = pyfr.writers.get_writer_by_extn(".vtu", writerArgs)
    print("Converting " + iFile + " to " + oFile)
    writer.write_out()


def get_pyfrs_files(pyfrsDirPath):
    pass


if __name__ == "__main__":

    args = parseArgs()
    args = setup_dirs(args)
    pyfrsList = get_pyfrs_list(args.solnDir)
    generate_vtu(
        args.vtuDir, args.solnDir, pyfrsList,
        args.mesh, args.overwrite, args.degree)