#!python3.8
import argparse
import os

#############
# functions #
#############

def ImSpiRE_parser():
    imspire_parser = argparse.ArgumentParser(prog='ImSpiRE',
    usage='%(prog)s [-h] <-i InputDir> <-c filtered_feature_bc_matrix.h5> <-s image.tif> [-n ProjectName] [-o OutputDir] [options]',
    formatter_class=argparse.RawDescriptionHelpFormatter,
    description='ImSpiRE is an Image-aided Spatial Resolution Enhancenment method for in situ capturing (ISC) datasets.')

    imspire_parser.add_argument('-v',
                                '--version',
                                action='version',
                                version='ImSpiRE 1.1.1',
                                help='''show version number of ImSpiRE and exit'''
                                )
    
    imspire_parser.add_argument('-i',
                                '--Input_Dir',
                                action='store',
                                type=str,
                                required=True,
                                help='''This indicates the path to the directory for input datafiles. For 10X Visium, it is similar to the standard output format of Space Ranger, which should contain a count file in the {Input_Dir} and a text file named "tissue_positions_list.csv" that describes the spot locations in the {Input_Dir}/spatial/. For ST, it should contain a count file and a text file named "pxl_pos.txt" that describes the spot locations in the {Input_Dir}. Note that the file "tissue_positions_list.csv" does not contain a header column, while the file "pxl_pos.txt" includes a header column and contains two columns, which represent the pixel coordinates of rows and columns of spots, respectively.'''
                                )
    
    imspire_parser.add_argument('-c',
                                '--Input_Count_File',
                                action='store',
                                type=str,
                                required=True,
                                help='''The input count file. It would typically be "filtered_feature_bc_matrix.h5" and "count_matrix.tsv" for 10X Visium and ST, respectively. Note that the count file of ST platform should be tab-delimited.'''
                                )
    
    imspire_parser.add_argument('-s',
                                '--Input_Section_Image_File',
                                action='store',
                                type=str,
                                required=True,
                                help='''The high-resolution tissue image, which should be a Tagged Image File Format (TIF or TIFF) file.'''
                                )
    
    imspire_parser.add_argument("-t",
                                '--Input_Image_Type',
                                action='store',
                                type=str,
                                choices=["H&E","IF"],
                                default="H&E",
                                help='''The types of staining, including Haematoxylin & Eosin (H&E) staining and  Immunofluorescence (IF) staining. DEFAULT: "H&E".'''
                                )
    
    imspire_parser.add_argument('-o',
                                '--Output_Dir',
                                action='store',
                                type=str,
                                default="./",
                                help='''The project directory, which is used to save all output files. DEFAULT: "./".'''
                                )
    
    imspire_parser.add_argument('-n',
                                '--Output_Name',
                                action='store',
                                type=str,
                                default="ImSpiRE",
                                help='''The project name, which is used to generate output file names as a prefix. DEFAULT: "ImSpiRE".'''
                                )

    imspire_parser.add_argument('-p',
                                '--Platform',
                                action='store',
                                type=str,
                                choices=["Visium","ST"],
                                default="Visium",
                                help='''The platform that generates the dataset, Visium or ST. DEFAULT: "Visium".'''
                                )
    
    imspire_parser.add_argument('-m',
                                '--Mode',
                                action='store',
                                type=int,
                                choices=[1,2],
                                default=1,
                                help='''Two types of extracted image features. When this parameter is set to 1, ImSpiRE will extract intensity and texture features of the image, which are the objective features of the image itself. When this parameter is set to 2, ImSpiRE will use CellProfiler to extract image features, which are more biologically significant. DEFAULT: 1.'''
                                )

    imspire_parser.add_argument('-O',
                                '--Overwriting',
                                action='store_true',
                                dest='overwriting_flag',
                                help='''The switch of overwriting. If add the parameter "-O", ImSpiRE will overwrite the exiting folders.'''
                                )
    
    imspire_parser.add_argument('--Verbose',
                                action='store_true',
                                dest='verbose_flag',
                                help='''The verbose flag. If add the parameter "--Verbose", ImSpiRE will verbose the output.'''
                                )

    imspire_parser.add_argument('--Random_State',
                                action='store',
                                type=int,
                                default=0,
                                help='''Fix the seed for reproducibility. DEFAULT: 0.'''
                                )

    imspire_parser.add_argument('--Switch_Preprocess',
                                action='store',
                                type=str,
                                choices=["ON","OFF"],
                                default="ON",
                                help='''The switch of basic filtering of spots and genes, ON or OFF. DEFAULT: "ON".'''
                                )
    
    imspire_parser.add_argument('--Threshold_MinCounts',
                                action='store',
                                type=int,
                                default=100,
                                help='''The minimum number of counts required for a spot to pass filtering, which is enabled only if "--Switch_SpotFilter" is "ON". DEFAULT: 100.'''
                                )
    
    imspire_parser.add_argument('--Threshold_MaxCounts',
                                action='store',
                                type=int,
                                default=10000,
                                help='''The maximum number of counts required for a spot to pass filtering, which is enabled only if "--Switch_SpotFilter" is "ON". DEFAULT: 10000.'''
                                )
    
    imspire_parser.add_argument('--Threshold_MitoPercent',
                                action='store',
                                type=float,
                                default=20,
                                help='''The maximum count percent of mitochondrial genes required for a spot to pass filtering, which is enabled only if "--Switch_SpotFilter" is "ON". DEFAULT: 20.'''
                                )
    
    imspire_parser.add_argument('--Threshold_MinSpot',
                                action='store',
                                type=int,
                                default=10,
                                help='''The minimum number of spots expressed required for a gene to pass filtering, which is enabled only if "--Switch_SpotFilter" is "ON". DEFAULT: 10.'''
                                )
    
    imspire_parser.add_argument('--ImageParam_CropSize',
                                action='store',
                                type=int,
                                default=100,
                                help='''The pixel size of each patch subimage. For example, "--ImageParam_CropSize 100" means each patch subimage is 100*100 pixels. DEFAULT: 100.'''
                                )
    
    imspire_parser.add_argument('--ImageParam_PatchDist',
                                action='store',
                                type=int,
                                default=100,
                                help='''The pixel distance between adjacent patches. DEFAULT: 100.'''
                                )
    
    imspire_parser.add_argument('--ImageParam_TotalChannelNumber',
                                action='store',
                                type=int,
                                choices=[3,4],
                                help='''The total number of channels, which is needed only if "--Input_Image_Type" is "IF". For example, "--ImageParam_TotalChannelNumber 3" means the TIFF file contain three channels.'''
                                )

    imspire_parser.add_argument('--ImageParam_DAPIChannel',
                                action='store',
                                type=int,
                                choices=[1,2,3,4],
                                help='''The channel of the DAPI, which is needed only if "--Input_Image_Type" is "IF". For example: "--ImageParam_DAPIChannel 1".'''
                                )

    imspire_parser.add_argument('--ImageParam_FiducialFrameChannel',
                                action='store',
                                type=int,
                                choices=[1,2,3,4],
                                help='''The channel of the fiducial frame, which is needed only if "--Input_Image_Type" is "IF". For example: "--ImageParam_FiducialFrameChannel 3".'''
                                )

    imspire_parser.add_argument('--FeatureParam_ProcessNumber',
                                action='store',
                                type=int,
                                default=10,
                                help='''The number of worker processes to create when extracting texture and intensity features, which is used when "-m" is 1. DEFAULT: 10.'''
                                )

    imspire_parser.add_argument('--FeatureParam_FeatureType',
                                action='store',
                                type=int,
                                choices=[0,1,2],
                                default=0,
                                help='''This determines which type of image features to use when "-m" is 1. 0 for both texture and intensity features, 1 for texture features only and 2 for intensity features only. DEFAULT: 0.'''
                                )

    imspire_parser.add_argument('--FeatureParam_ClipLimit',
                                action='store',
                                type=float,
                                default=0.01,
                                help='''The clipping limit, which is used when "-m" is 1. It is normalized between 0 and 1, with higher values representing more contrast. DEFAULT: 0.01.'''
                                )

    imspire_parser.add_argument('--FeatureParam_IterCount',
                                action='store',
                                type=float,
                                default=50,
                                help='''Number of iterations Grabcut image segmentation algorithm should make before returning the result. DEFAULT: 50.'''
                                )

    imspire_parser.add_argument('--CellProfilerParam_Pipeline',
                                action='store',
                                type=str,
                                default="Cellprofiler_Pipeline_HE.cppipe",
                                help='''The path to the CellProfiler pipline. It would be better to use different piplines for H&E and IF samples. For H&E samples, "Cellprofiler_Pipeline_HE.cppipe" is recommended. For IF samples, "Cellprofiler_Pipeline_IF_C3/4.cppipe" is recommended based on the total number of channels. In the docker image, the pipelines are stored in "/root". You can also download them from github to your own working directory. DEFAULT: "Cellprofiler_Pipeline_HE.cppipe".'''
                                )

    imspire_parser.add_argument('--CellProfilerParam_KernelNumber',
                                action='store',
                                type=int,
                                default=10,
                                help='''This option specifies the number of kernel to use to run CellProfiler. DEFAULT: 10.'''
                                )

    imspire_parser.add_argument('--OptimalTransportParam_Alpha',
                                action='store',
                                type=float,
                                default=0.5,
                                help='''The constant interpolating between image features cost matrices and locations cost matirces, ranging from 0 to 1. For example, "--OptimalTransportParam_Alpha 0.5" means ImSpiRE will equally consider the weight of similarity from the saptial and image dimensions. The larger the value of alpha is, the more ImSpiRE considers the weight of similarity from the image dimension. DEFAULT: 0.5.'''
                                )

    imspire_parser.add_argument('--OptimalTransportParam_Beta',
                                action='store',
                                type=float,
                                default=0.5,
                                help='''The trade-off parameter of Fused-gromov-Wasserstein transport ranging from 0 to 1. DEFAULT: 0.5.'''
                                )

    imspire_parser.add_argument('--OptimalTransportParam_NumNeighbors',
                                action='store',
                                type=int,
                                default=5,
                                help='''The number of neighbors for nearest neighbors graph. DEFAULT: 5.'''
                                )

    imspire_parser.add_argument('--OptimalTransportParam_Epsilon',
                                action='store',
                                type=float,
                                default=0.001,
                                help='''The entropic regularization term with value greater than 0. DEFAULT: 0.001.'''
                                )

    imspire_parser.add_argument('--OptimalTransportParam_NumIterMax',
                                action='store',
                                type=int,
                                default=10,
                                help='''Max number of iterations when solving the OT problem. DEFAULT: 10.'''
                                )

    return imspire_parser

if __name__ == '__main__':
    
    imspire_parser=ImSpiRE_parser()
    args = imspire_parser.parse_args()

    if args.Input_Dir is None:
        imspire_parser.print_help()
        os._exit(0)
    if args.Input_Count_File is None:
        imspire_parser.print_help()
        os._exit(0)
    if args.Input_Section_Image_File is None:
        imspire_parser.print_help()
        os._exit(0)

    from imspire_object import *
    imspire_param=ImSpiRE_Parameters()
    #Basic Params#
    imspire_param.BasicParam_OutputDir=args.Output_Dir
    imspire_param.BasicParam_OutputName=args.Output_Name
    imspire_param.BasicParam_InputDir=args.Input_Dir
    imspire_param.BasicParam_InputCountFile=args.Input_Count_File
    imspire_param.BasicParam_InputImageFile=args.Input_Section_Image_File
    imspire_param.BasicParam_InputImageType=args.Input_Image_Type
    imspire_param.BasicParam_Verbose=args.verbose_flag
    imspire_param.BasicParam_RandomState=args.Random_State
    imspire_param.BasicParam_Overwriting=args.overwriting_flag
    imspire_param.BasicParam_PlatForm=args.Platform
    imspire_param.BasicParam_Mode=args.Mode
    #Spot Preprocess#
    imspire_param.Switch_Preprocess=True if args.Switch_Preprocess=="ON" else False
    imspire_param.Threshold_MinCounts=args.Threshold_MinCounts
    imspire_param.Threshold_MaxCounts=args.Threshold_MaxCounts
    imspire_param.Threshold_MitoPercent=args.Threshold_MitoPercent
    imspire_param.Threshold_MinSpot=args.Threshold_MinSpot
    #Image segment#
    imspire_param.ImageParam_CropSize=args.ImageParam_CropSize
    imspire_param.ImageParam_PatchDist=args.ImageParam_PatchDist
    imspire_param.ImageParam_TotalChannelNumber=None if args.Input_Image_Type=="H&E" else args.ImageParam_TotalChannelNumber
    imspire_param.ImageParam_DAPIChannel=None if args.Input_Image_Type=="H&E" else args.ImageParam_DAPIChannel
    imspire_param.ImageParam_FiducialFrameChannel=None if args.Input_Image_Type=="H&E" else args.ImageParam_FiducialFrameChannel
    ## Feature extraction#
    imspire_param.FeatureParam_ProcessNumber=args.FeatureParam_ProcessNumber
    imspire_param.FeatureParam_FeatureType=args.FeatureParam_FeatureType
    imspire_param.FeatureParam_ClipLimit=args.FeatureParam_ClipLimit
    imspire_param.FeatureParam_IterCount=args.FeatureParam_IterCount
    #CellProfiler Params#
    imspire_param.CellProfilerParam_Pipeline=args.CellProfilerParam_Pipeline
    imspire_param.CellProfilerParam_KernelNumber=args.CellProfilerParam_KernelNumber
    #OT Solver Params#
    imspire_param.OptimalTransportParam_Alpha=args.OptimalTransportParam_Alpha
    imspire_param.OptimalTransportParam_Beta=args.OptimalTransportParam_Beta
    imspire_param.OptimalTransportParam_NumNeighbors=args.OptimalTransportParam_NumNeighbors
    imspire_param.OptimalTransportParam_Epsilon=args.OptimalTransportParam_Epsilon
    imspire_param.OptimalTransportParam_NumIterMax=args.OptimalTransportParam_NumIterMax

    imspire=ImSpiRE(imspire_param)
    imspire.run()
    #imspire.output_supplementary_results()

















