//
//  mh5000
//
//  Copyright (c) 2017 Michael Heras
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307,
//  USA.
//
#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <cstdlib>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <getopt.h>
#include <vector>
#include </usr/include/Imlib2.h>
#include "files.h"
#include "img.h"
#include "options.h"

enum
{
    T, TH, TV, TD, THV, ST, BUTT
};

const char *tile_opts[] =
{
    [T]    = "n",
    [TH]   = "h",
    [TV]   = "v",
    [TD]   = "d",
    [THV]  = "hv",
    [ST]   = "st",
    [BUTT] = NULL
};

enum
{
    FD, FH, FV, FAH, FAV, FATH, FATV, BUTT2
};

 const char *flip_opts [] =
{

    [FD]    = "d",
    [FH]    = "h",
    [FV]    = "v",
    [FAH]   = "ah",
    [FAV]   = "av",
    [FATH]  = "ath",
    [FATV]  = "atv",
    [BUTT2] = NULL
};

enum
{
    RC, RA, RD, SOR, BUTT3
};

 const char *rand_opts [] =
{
    [RC]    = "rc", // random 2 colors
    [RA]    = "ra", // random angle
    [RD]    = "rd", // random distance
    [SOR]   = "sor", // system over ride - randomizes everything.
    [BUTT3] = NULL
};



void init_options(int argc, char **argv)
{
   // std::memset(&opts, 0, sizeof(options));
    std::memset(&img, 0, sizeof(image_data));
    img.file_number = -1;
    parse_options(argc, argv);
}

void parse_options(int argc, char **argv)
{
    static char string_options [] = "rFfoh::a:t:s:n:i:d:c::z:O:S:";
//  no_argument  0
// required_argument 1   ( : ) to indicate that it takes a required argument
// optional_argument 2  ( :: ), its argument is optional
    static struct option long_options[] =
    {
// a b c d e f g h i j k l m n o p q r s t u v w x y z
        {"fullscreen",      0,  0,  'f'}, // fills screen streaching image
        {"fill",            0,  0,  'F'}, // fills image using aspect ratio
        {"center",          2,  0,  'c'}, // Center and resize-center
        {"tile",            1,  0,  't'}, // arg n=normal v = vertical etc.. SUBOPTS
        {"angle",           1,  0,  'a'}, // angle between 2 colors
        {"solid",           1,  0,  's'}, // solid color
        {"distance",        1,  0,  'd'}, // distance between 2 colors
        {"randomize",       0,  0,  'r'}, // sets random files
        {"delay",           1,  0,  'z'}, // sets delay timer
        {"file-number",     1,  0,  'n'}, // gets user specifed file by number
        {"help",            0,  0,  'h'}, // help
        {"version",         0,  0,  'v'}, // version
        {"address",         1,  0,  'O'}, // file or path to dir for images
        {"single",          1,  0,  'S'}, // single image
        {"add",             1,  0,  200}, // for adding two colors
        {"rc",              2,  0,  201}, // sets two random colors plus more
        {"ra",              0,  0,  202}, // random angle
        {"rd",              0,  0,  203}, // random distance
        {"over-ride",       0,  0,  204}, // over rides everything and sets random everything
        {"ordered",         0,  0,  'o'}, // sets images to show in alphabit order
        {"sc",              0,  0,  205}, // single random color
        {"st",              2,  0,  207}, // space tile
        {"fi",              1,  0,  208}, // flip image
        {"printlist",       0,  0,  209}, // prints files on intake
        {"over-drive",      0,  0,  210}, // over drive does not do just colors, only random images
        {"p",               0,  0,  211}, // print list file
        {"rotate-angle",    1,  0,  212}, // gets degrees of rotation
        {"m",               0,  0,  213}, // moves image down and across screen
        {"at",              0,  0,  214}, //tile image at an angle
        {"rotate",          0,  0,  215}, //rotates image
        {0,                 0,  0,    0}
    }; // end options

    int ol = 0;
    unsigned int w,h;
    int option_index = 0;
    char *value;
    char oopsX[10];
    char *subopts;
    extern char *optarg;
    extern int optind;

    while (( ol = getopt_long_only(argc, argv, string_options, long_options,&option_index) ) != -1)
    {
        switch (ol)
        {
        case 'S':
            if (optarg == nullptr)
            {
                usage(argv);
            }
            else
            {
                opts.path = strdup(optarg);
                opts.which_file_type = 1;
                opts.single_file = 1;
                //                put_in_one_file( opts.dfile, opts.path);

            }
            break;
        case 'O':
               opts.pathORDir = optarg;


                if ( checkFileExt ( getFileExt(opts.pathORDir, 0) ) == 1 )
                { // check to make sure it is not a single image file
                    std::cout<<"\n"<<"Has to be file containing list of images"<<"\n"
                    <<"with absolute paths, or, a directory containing images."<<std::endl
                    <<"For a Single Image use the -S option."<<"\n"<<"See man page for more "
                    "information."<<std::endl<<std::endl;
                    set_oops_color();
                    Load_OOPs_Image();
                    exit(1);
                }
                try // it already checked to be sure it was not a single image file
                {   //so taking that into account the checkiffile function
                    //works on process of elimination.
                    //
                    //1 for directory load files
                    //2 for file load files
                    if (  checkIfDirectory(opts.pathORDir) )
                    {
                        opts.which_file_type = 2;
                    }
                    else if ( checkIfFile (opts.pathORDir) )
                    {
                        opts.which_file_type = 3;
                    }
                    else
                    {
                        std::cout<<"Not a valid path "<<opts.pathORDir<<std::endl<<std::endl;
                        set_oops_color();
                        Load_OOPs_Image();
                        exit(1);
                    }
                }
                catch (...)
                {
                    std::cerr<<"Something crazy just happened."<<std::endl;
                    set_oops_color();
                    Load_OOPs_Image();
                    exit(1);
                }
            break;
        case 'f': //fullscreen
            img.mode = FULLSCREEN;
            break;
        case 'F': // fill

            img.mode = FILL;
            break;
        case 213:
            img.mode = MOVEIMAGE;

            mvi.randomDirection();
            mvi.start();
            break;
        case 'c': // center / resize center
            //check ahead by 1 to see if = was forgotten to be added
            // if user is trying to resize the image. Retruns 0
            // if it is a proper format for size using an x.


            if (optarg == NULL)
            {
                img.mode = CENTER;
            }
            else

            {
                strcpy(img.findX, optarg);
                strcpy(oopsX, img.findX);
                if (gettingWidthHeight(img.findX, &w,&h) == -1)
                {
                    BadFindX(oopsX);
                    exit(1);
                }
                else
                {
                    img.set_newimg_w = w;
                    img.set_newimg_h = h;
                    img.mode = DCENTER;
                }
            }

            break;
        case 207: //space tile
           // std::cout<<"space tile optarg "<<optarg<<std::endl;
            if (optarg == NULL)
            {
                img.mode = SPACE_TILE;
            }
            else
            {   std::cout<<"optarg "<<optarg<<std::endl;
                img.flip = atoi(optarg);
                if (img.flip > 7)
                {
                    printf("Value < %d > sets between 1 ... 6\n7 is for random modes\n", img.flip);
                    set_oops_color();
                    Load_OOPs_Image();
                    exit(1);
                }
            }
            if(img.flip == 7)
                img.flips_mode = 1;

            img.mode = SPACE_TILE;
        //    std::cout<<"space tile img.mode "<<(int)img.mode<<std::endl;
            break; // ############ COLORS ########
        case 's': //solid
            img.color_flag = 1;
            img.solidColor = strdup(optarg);
            break;
        case 200:
            //--add with or without distance

            img.color_flag = 2;

            img.set_2_colors += 1;
            img.color1 = strdup(optarg);

            //get them both for later.
            switch (img.set_2_colors)
            {
            case 1:
                img.color2 = img.color1;
                break;
            default:
                break;

            }
            break;
        case 205: // random solid color
            img.color_flag = 3;
            break;
        case 201: // Random Colors
            img.color_flag = 4;
            if (optarg == NULL)
            {
                img.set_random_color_num = 1;
            }
            else if (atoi(optarg) > MAX_SHOW_COLORS)
            {

                BeyondMaxColors(optarg);
                exit(1);
            }
            else
            {
                img.set_random_color_num = atoi(optarg);
            }
            break;

        case 'd': // distance
            img.distance = atoi(optarg);

            if (img.distance == 0)
            {
                printf("Missing Distance < %d >\n", img.distance);
                set_oops_color();
                Load_OOPs_Image();
                exit(1);
            }
            break;

        case 'a': //angle
            // sets a angle to two colors gradients
            img.angle = atoi(optarg);
            break;
        case 'r': // random files
            img.set_randomize = 1;
            break;
        case 'z': //sets timer time
            if (optarg == NULL)
                printf("< %s >\n",optarg);
            else
                if (seconds_or_minutes(optarg) != -1)
                {
                    img.time = seconds_or_minutes(optarg);
                }
                else
                {
                    set_oops_color();
                    std::cout<<"0"<<std::endl;
                    Load_OOPs_Image();
                    warning_message();
                }
            break;
        case 'n': //number file to display
            img.file_number = atoi(optarg);
            break;
        case 'h':
            //printf("Help: You're telling me?\nTry man mh5000\n");
            usage(argv);
            exit(0);
            break;
        case 202: //random angle
            img.angle_flag = 1;
            get_randoms();
            break;
        case 203: // random distance
            img.angle_flag = 2;
            get_randoms();
            break;
        case 204: // -over-ride-system
            img.set_over_ride_system = 1;
            break;
        case 'o':  // order list
            img.set_ordered_list = 1;
            break;
        case 209:
            img.printlistintake = 1;
            break;
        case 210:
            img.set_over_drive = 1;
            break;
        case 211:
            img.printlistintake = 3;
            break;
        case 212:
            img.rotate_angle_flag = 1;
            img.rotate_angle_num = rotate_angle(atoi(optarg));
            break;
        case 214:
            img.mode = ANGLED_TITLE;
            break;
        case 215:
            img.mode = ROTATE;
            break;
        case 'v':
          //  version_message();
            break;
        case '?':
            printf("What did you forget?  Think about it.\n");
            set_oops_color();
            Load_OOPs_Image();
            exit(1);
            break;
        case 't': // sub img one tile
            subopts = optarg;

            while (*subopts != '\0')
            {
                switch (getsubopt (&subopts, (char **)tile_opts, &value))
                {
                case T:
                    if (value == NULL)
                    {
                        img.mode = TILE;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);

                       if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {
                            img.set_newimg_w = w;
                            img.set_newimg_h = h;
                            img.mode = DTILE;
                        }
                    }
                    break;
                case TH:
                    if (value == NULL)
                    {
                        img.mode = TILEH;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);

                       if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                           BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {
                            img.set_newimg_w = w;
                            img.set_newimg_h = h;

                            img.mode = DTILEH;
                        }
                    }
                    break;
                case TV:
                    if (value == NULL)
                    {
                        img.mode = TILEV;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);

                       if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {
                            img.set_newimg_w = w;
                            img.set_newimg_h = h;
                            img.mode = DTILEV;
                        }
                    }
                    break;
                case TD:


                    if (value == NULL)
                    {
                        img.mode = TILED;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);

                        if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {

                            img.set_newimg_w = w;
                            img.set_newimg_h = h;

                            img.mode = DTILED;
                        }
                    }
                    break;
                case THV:

                    if (value == NULL)
                    {
                        img.mode = TILEHV;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);

                       if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {
                            img.set_newimg_w = w;
                            img.set_newimg_h = h;
                            img.mode = DTILEHV;
                        }
                    }
                    break;
                case ST:
                    if ( value == NULL)
                    {
                        img.mode =SPACE_TILE;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);
                        if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {
                            img.set_newimg_w = w;
                            img.set_newimg_h = h;
                            img.mode = DTILEHV;
                        }
                    }
                    break;
                default:
                    printf ("Unknown tiling Option  < %s >\n", value);
                    tiling_options_help(argv);
                    set_oops_color();
                    Load_OOPs_Image();
               //     warning_message();
                    exit(1);
                    break;
                }
            } // end off while
            break;
        case 208: //flip image
            subopts = optarg;
            while (*subopts != '\0')
            {
                switch (getsubopt (&subopts, (char **)flip_opts, &value))
                {
                case FD:
                    if (value == NULL)
                    {
                        img.mode = FLIPIMGD;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);
                        if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {

                            img.set_newimg_w = w;
                            img.set_newimg_h = h;

                            img.mode = DFLIPIMGD;
                        }
                    }
                    break;
                case FH:
                    if (value == NULL)
                    {
                        img.mode = FLIPIMGH;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);
                        if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                            BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {

                            img.set_newimg_w = w;
                            img.set_newimg_h = h;

                            img.mode = DFLIPIMGH;
                        }
                    }
                    break;
                case FV:
                    if (value == NULL)
                    {
                        img.mode = FLIPIMGV;
                    }
                    else
                    {
                        strcpy(img.findX, value);
                        strcpy(oopsX, img.findX);
                        if (gettingWidthHeight(img.findX, &w,&h) == -1)
                        {
                           BadFindX(oopsX);
                            exit(1);
                        }
                        else
                        {
                            img.set_newimg_w = w;
                            img.set_newimg_h = h;

                            img.mode = DFLIPIMGV;
                        }
                    }
                    break;
                case FAH:
                    img.mode = FLIPAH;
                    break;
                case FAV:
                    img.mode = FLIPAV;
                    break;
                case FATH:
                    img.mode = FLIPAVTH;
                    break;
                case FATV:
                    img.mode = FLIPAVTV;
                    break;
                default:
                    //Second suboption.
                    printf ("Unknown fliping Option < %s >\n", value);
                    flipping_options_help(argv);
                    set_oops_color();
                    Load_OOPs_Image();
                    //warning_message();
                    exit(1);
                    break;
                } // end second switch subopts
            } // end second while off subopts
            break; // break off of inner subopts switch
        default:
            printf("Unknown general Option < %s >\n", optarg);
            set_oops_color();
            Load_OOPs_Image();
            exit(1);
            break;

        } // end switch
    } // end

    if ( img.set_over_ride_system != 1 && img.mode == 0 && img.set_over_drive != 1 &&
            img.set_random_color_num < 1 && img.color_flag == 0 && opts.single_file == 0)
    {
        std::cout<<"1"<<"\n";
        set_oops_color();
        Load_OOPs_Image();
        warning_message();
    }
//    if ((int)img.mode < 1 && opts.FilesLoaded == 1 && img.set_over_drive != 1 ){ set_oops_color(); std::cout<<"2"<<std::endl; warning_message();}

    if(optind == argc)
    {
        if ( ( (img.set_ordered_list == 1 )  || ( img.set_randomize == 1) ) && (opts.which_file_type == 0 ) )
        {
            std::cout<<"1: File Source is (NULL)"<<std::endl;
            set_oops_color();
            Load_OOPs_Image();
            exit(1);
        }
        if(  ((img.set_over_ride_system == 1 ) || (img.set_over_drive == 1) )  && (opts.which_file_type == 0))
        {
            std::cout<<"Just so you know. You're not "<<"\n"<<"going to get any images like that."<<std::endl;
            set_oops_color();
            Load_OOPs_Image();
            exit(1);
        }
    }

    if ( optind < argc)
    {
        std::cout<<"Badly formed command line. Please Fix"<<"\n"
        <<"Error < "<<argv[optind]<<" >"<<std::endl;
        set_oops_color();
        Load_OOPs_Image();
        exit(1);
    }


    optind = 0;
} //end function
void check_options(void)
{
    if(img.set_randomize == 1 && img.set_ordered_list == 1)
    {
        img.set_randomize = 0;
    }

    if (img.set_over_drive == 1)
    {
        // if over ride is selected, make sure it over rides everything.
        img.set_randomize = 1;
        img.set_random_color_num = 0;
        img.set_ordered_list = 0;
        img.file_number = 0;
        img.color_flag = 0;
        img.mode = 0;
    }
}

void flipping_options_help(char **argv)
{
    std::cout<<argv[0]<<" -fi <sub options> "<<std::endl
    <<"d : Image is flipped diagonally."<<std::endl
    <<"h : Image is flipped horizontally."<<std::endl
    <<"v : Image is flipped vertically."<<std::endl
    <<"av : angled with image rendered as vertical by imlib2."<<std::endl
    <<"ath : angled with image rendered tile horizontal by imlib2."<<std::endl
    <<"atv : angled with image rendered tile vertical by imlib2."<<std::endl
    <<std::endl
    <<"These all produce a different effect on the image itself."<<std::endl
    <<"As well as how it is displayed."<<std::endl;

}
void tiling_options_help(char **argv)
{
    std::cout<<argv[0]<<" -t <sub option> "<<std::endl
    <<"All Images  are tiled across the screen at"<<std::endl
    <<"1/3 scale."<<std::endl<<std::endl
    <<"n : Normal tile across the screen"<<std::endl
    <<"h : image is rendered horizontally by imlib2."<<std::endl
    <<"v : image is rendered vertically by imlib2"<<std::endl
    <<"d : image is rendered diagonally by imlib2."<<std::endl
    <<"hv : image is rendered horizontally and vertically by imlib2."<<std::endl
    <<"st : image is set tiled with spaces between them. A random two color combonation is placed"<<std::endl
    <<"between the tiles."<<std::endl;
}
