//
//  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 <fstream>
#include <iostream>
#include <cstring>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
//#include </usr/include/Imlib2.h>
#include <string>
#include <vector>
#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>
#include "options.h"
#include "files.h"
#include "imgfunctions.hpp"
#include "img.h"

#define OPPS_IMAGE "/etc/mh5000/opps_try_001.jpg"
#define VERSION "1.3.5"

imlib_data imgdata;
image_data img;
Color c;
RandomColors rc;
move_image mi;
mvImage mvi;

void setup_images()
{

    imgdata.modifier = NULL;
    imgdata.context = imlib_context_new();
    imlib_context_push(imgdata.context);
    imlib_context_set_display(imgdata.display);

    imgdata.vis = DefaultVisual(imgdata.display, 0);
    imgdata.cm = DefaultColormap(imgdata.display, 0);
    img.screenW = DisplayWidth(imgdata.display, 0);
    img.screenH = DisplayHeight(imgdata.display, 0);

    img.depth = DefaultDepth(imgdata.display, 0);

    imgdata.pixmap = XCreatePixmap(imgdata.display, RootWindow(imgdata.display, 0), img.screenW, img.screenH, img.depth);

    imlib_context_set_display(imgdata.display);
    imlib_context_set_visual(imgdata.vis);
    imlib_context_set_colormap(imgdata.cm);
    imlib_context_set_drawable(imgdata.pixmap);
    imlib_context_set_color_range(imlib_create_color_range());

    imgdata.buffer = imlib_create_image(img.screenW, img.screenH);

    set_buffer();

    imlib_context_set_color(0, 0, 0, 255);
    imlib_image_fill_rectangle(0, 0, img.screenW, img.screenH);
    imlib_context_set_dither(1);
    imlib_context_set_blend(1);
    imgdata.modifier = imlib_create_color_modifier();
    imlib_context_set_color_modifier(imgdata.modifier);
}

void load_image()
{ //std::cout<<"in load image"<<"image mode "<<(int)img.mode<<"img.flip "<<img.flip<<std::endl;
    int w = 0, h = 0, top = 0, left = 0, x = 0, y = 0;
    int ww = 0, hh = 0;
    int newW = 0, newH = 0;
    double aspect;
    int destination_x = 0, destination_y = 0;
    int angle_x = 0, angle_y = 0;

    aspect = ((double) img.screenW) / w;

    left = (img.screenW - w) / 2;
    top = (img.screenH - h) / 2;

    if (opts.single_file == 1)
    {
        if ( Load_single_Image() )
        {
            set_oops_color();
            warning_message();
            exit(1);
        }

    }
    else
        load_image_err();

    set_image();
    w = imlib_image_get_width();
    h = imlib_image_get_height();
    set_buffer();
 //   std::cout<<"enting load_image"<<  std::endl;
    switch (img.mode)
    {
       case FULLSCREEN: //f
        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0,w, h, 0,0, img.screenW, img.screenH);
        break;
    case FILL: //F

        top = (img.screenH - (int) (h * get_aspect(h))) / 2;
        left = (img.screenW - (int) (w * get_aspect(h))) / 2;

        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left, top, get_adjusted_by_aspect(get_aspect(h),w), get_adjusted_by_aspect(get_aspect(h),h));
        break;
    case CENTER:
        if (w >= img.screenW || h >= img.screenH )
        {
            aspect = (double) img.screenH / (double) h;

            top = (img.screenH - (int) (h * aspect)) / 2;
            left = (img.screenW - (int) (w * aspect)) / 2;

            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left, top, get_adjusted_by_aspect(get_aspect(h),w), get_adjusted_by_aspect(get_aspect(h),h));
        }
        else
        {
            top = (img.screenH - h) / 2;
            left = (img.screenW - w) / 2;
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left, top, w, h);
        }
        break;
    case TILE:
          //(original height / original width) x wanted size = adjusted mesurment
          //get 1/3 screensize image to tile
        if ( h > (img.screenH / 3))
        {
          newH = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
          newW = (get_adjusted_by_aspect(get_aspect(h),w) / 3);
        }
        else
        {
            newH = h;
            newW = w;
        }

        top = (img.screenH - (int) (h * get_aspect(h))) / 2;
        left = (img.screenW - (int) (w * get_aspect(h))) / 2;

        for (; left > 0; left -= newW)
        {}
            for (; top > 0; top -= newH)
            {}

        for (x = left; x < img.screenW; x += newW) {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x, y, newW, newH);
        }
        break;
    case TILEH:
        set_image();
        imlib_image_flip_horizontal();
        set_blend();
        set_buffer();

        //(original height / original width) x wanted size = adjusted mesurment
        //get 1/3 screensize image to tile
        if ( h > (img.screenH / 3))
        {
          newH = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
          newW = (get_adjusted_by_aspect(get_aspect(h),w) / 3);
        }
        else
        {
            newH = h;
            newW = w;
        }
        top = (img.screenH - (int) (h * get_aspect(h))) / 2;
        left = (img.screenW - (int) (w * get_aspect(h))) / 2;


        for (; left > 0; left -= newW)
        {}
            for (; top > 0; top -= newH)
            {}

        for (x = left; x < img.screenW; x += newW)
            for (y = top; y < img.screenH; y += newH)

        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x,y, newW, newH);
        break;
    case TILEV:
        set_image();
        imlib_image_flip_vertical();
        set_blend();
        set_buffer();

        //(original height / original width) x wanted size = adjusted mesurment
        //get 1/3 screensize image to tile
        if ( h > (img.screenH / 3))
        {
          newH = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
          newW = (get_adjusted_by_aspect(get_aspect(h),w) / 3);
        }
        else
        {
            newH = h;
            newW = w;
        }

        top = (img.screenH - (int) (h * get_aspect(h))) / 2;
        left = (img.screenW - (int) (w * get_aspect(h))) / 2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW) {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x, y, newW, newH);
        }
        break;
    case TILEHV:
        imlib_image_tile();

        //(original height / original width) x wanted size = adjusted mesurment
        //get 1/3 screensize image to tile
        if ( h > (img.screenH / 3))
        {
          newH = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
          newW = (get_adjusted_by_aspect(get_aspect(h),w) / 3);
        }
        else
        {
            newH = h;
            newW = w;
        }

        top = (img.screenH - (int) (h * get_aspect(h))) / 2;
        left = (img.screenW - (int) (w * get_aspect(h))) / 2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
        {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x, y, newW, newH);
        }
        break;
    case TILED:
        set_image();
        imlib_image_flip_diagonal ();
        set_blend();
        set_buffer();

        //(original height / original width) x wanted size = adjusted mesurment
        //get 1/3 screensize image to tile
        if ( h > (img.screenH / 3))
        {
          newW = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
          newH = (get_adjusted_by_aspect(get_aspect(h),w) / 3);
        }
        else
        {
            newH = h;
            newW = w;
        }

        top = (img.screenH - (int) (h * get_aspect(h))) / 2;
        left = (img.screenW - (int) (w * get_aspect(h))) / 2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
        {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w, x, y, newW, newH);
        }

        break;
    case FLIPIMGH:
        set_image();
        imlib_image_flip_horizontal();
        set_blend();
        set_buffer();

        top = (img.screenH - get_adjusted_by_aspect(get_aspect(h),h))/ 2;
        left = ( img.screenW - get_adjusted_by_aspect(get_aspect(h),w)) / 2;
        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w,h,left,top, get_adjusted_by_aspect(get_aspect(h),w) ,get_adjusted_by_aspect(get_aspect(h),h));
        break;
    case FLIPIMGV:
        set_image();
        imlib_image_flip_vertical();
        set_blend();
        set_buffer();

        top = (img.screenH - get_adjusted_by_aspect(get_aspect(h),h))/ 2;
        left = ( img.screenW - get_adjusted_by_aspect(get_aspect(h),w)) / 2;
        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w,h,left,top,
        get_adjusted_by_aspect(get_aspect(h),w) ,
        get_adjusted_by_aspect(get_aspect(h),h));
        break;
    case FLIPIMGD:
        set_image();
        imlib_image_flip_diagonal ();
        set_blend();
        set_buffer();

        if (h > img.screenW)
        {
            top = (img.screenH - get_adjusted_by_aspect(get_aspect(h),h))/ 2;
            left = ( img.screenW - get_adjusted_by_aspect(get_aspect(w),w)) / 2;
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w,left,top,
            get_adjusted_by_aspect(get_aspect(h),h) ,
            get_adjusted_by_aspect(get_aspect(h),h));
        }
        else
        {
            left = (img.screenW - h) / 2;
            top = (img.screenH - w) / 2;
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w,left,top,h,w);
        }
        break;
     case FLIPAH: //Experimental Flip Image on an angle
        set_image();
        imlib_image_flip_horizontal();
        set_blend();
        set_buffer();

        destination_x = ((img.screenH / 2) - (img.screenW / 4.35));
        destination_y = (img.screenW / 2.3);
        angle_x = (img.screenW / 3);
        angle_y = (img.screenH / 2);


        //  imlib_blend_image_onto_image_at_angle (Imlib_Image source_image, char merge_alpha,
        //  int source_x, int source_y, int source_width, int source_height,
        //  int destination_x, int destination_y, int angle_x, int angle_y)

                                    //right side  left side image
        imlib_blend_image_onto_image_at_angle(imgdata.image, 0, 0,0,w,h,
        destination_y, destination_x, angle_x , angle_y);
        break;
    case FLIPAV: //Experimental Flip Image on an angle
        set_image();
        imlib_image_flip_vertical();
        set_blend();
        set_buffer();

        destination_x = ((img.screenH / 2) - (img.screenW / 4.35));
        destination_y = (img.screenW / 2.344);
        angle_x = (img.screenW / 3);
        angle_y = (img.screenH / 2);
                                                    //right side  left side image
        imlib_blend_image_onto_image_at_angle(imgdata.image, 0, 0,0,w,h,
        destination_y, destination_x, angle_x , angle_y);
        break;
  case FLIPAVTH: //Experimental Flip Image on an angle
        set_image();
        imlib_image_tile_horizontal();
        //        imlib_image_flip_vertical();
        set_blend();
        set_buffer();

        destination_x = ((img.screenH / 2) - (img.screenW / 4.35));
        destination_y = (img.screenW / 2.344);
        angle_x = (img.screenW / 3);
        angle_y = (img.screenH / 2);
                                                    //right side  left side image
        imlib_blend_image_onto_image_at_angle(imgdata.image, 0, 0,0,w,h,
        destination_y, destination_x, angle_x , angle_y);
        break;
 case FLIPAVTV: //Experimental Flip Image on an angle
        set_image();
        imlib_image_tile_vertical();
        //        imlib_image_flip_vertical();
        set_blend();
        set_buffer();

        destination_x = ((img.screenH / 2) - (img.screenW / 4.35));
        destination_y = (img.screenW / 2.344);
        angle_x = (img.screenW / 3);
        angle_y = (img.screenH / 2);
                                                    //right side  left side image
        imlib_blend_image_onto_image_at_angle(imgdata.image, 0, 0,0,w,h,
        destination_y, destination_x, angle_x , angle_y);
        break;
    case ANGLED_TITLE:
        angled_tiling(w,h);
        break;
    case ROTATE:
        moveItInCircles(w,h);
        break;
    case DCENTER:
        if (img.set_newimg_w >= img.screenW || img.set_newimg_h  >= img.screenH )
        {
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, 0, 0,
            img.screenW, img.screenH);
        }
        else
        {
            left = (img.screenW - img.set_newimg_w) / 2;
            top =  (img.screenH - img.set_newimg_h) / 2;
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left,
            top, img.set_newimg_w, img.set_newimg_h);
        }
        break;
    case DTILE:
        newW = img.set_newimg_w;
        newH = img.set_newimg_h;
        if (newW > img.screenW)
            newW = (img.screenW / 2);

        if (newH > img.screenH)
            newH = (img.screenH / 2);

        left = (img.screenW - w) / 2;
        top = (img.screenH - h) /2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
        {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x,
                y, newW, newH);
        }
        break;
    case DTILEH:
        imlib_image_tile_horizontal();
        newH = img.set_newimg_h;
        newW = img.set_newimg_w;

        //set imagePicture size x y
        left = (img.screenW - newW) / 2;
        top = (img.screenH - newH) /2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
            for (y = top; y < img.screenH; y += newH)

        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x, y, newW, newH);
        break;
    case DTILEV:
        set_image();
        imlib_image_flip_vertical();
        set_blend();
        set_buffer();

        newH = img.set_newimg_h;
        newW = img.set_newimg_w;


        left = (img.screenW - newW) / 2;
        top = (img.screenH - newH) /2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
        {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x, y, newW, newH);
        }
        break;
    case DTILEHV:
        set_image();
        imlib_image_tile();
        imlib_image_tile_horizontal();
        set_blend();
        set_buffer();

        newH = img.set_newimg_h;
        newW = img.set_newimg_w;

        left = (img.screenW - newW) / 2;
        top = (img.screenH - newH) /2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
        {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, x, y, newW, newH);
        }
        break;
      case DTILED:
        newH = img.set_newimg_h;
        newW = img.set_newimg_w;

        set_image();
        imlib_image_flip_diagonal ();
        set_blend();
        set_buffer();
        imlib_image_tile_vertical();

        left = (img.screenW - newW) / 2;
        top = (img.screenH - newH) /2;

        for (; left > 0; left -= newW) {}
            for (; top > 0; top -= newH) {}

        for (x = left; x < img.screenW; x += newW)
        {
            for (y = top; y < img.screenH; y += newH)
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w, x, y, newW, newH);
        }
        break;
    case DFLIPIMGH:
        set_image();
        imlib_image_flip_horizontal();
        set_blend();
        set_buffer();
        newH = img.set_newimg_h;
        newW = img.set_newimg_w;

        // if imagePicture screenW or screenH is greater then screen then
        // makes imagePicture
            if (newW >= img.screenW || newH >= img.screenH )
            {
                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, 0, 0, img.screenW, img.screenH);
            }
            else
            {
                left = (img.screenW - newW) / 2;
                top =  (img.screenH - newH) / 2;

                imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left, top, newW, newH);
            }
        break;
    case DFLIPIMGV:
        set_image();
        imlib_image_flip_vertical ();
        set_blend();
        set_buffer();
        newH = img.set_newimg_h;
        newW = img.set_newimg_w;

        if (w >= img.screenW || h >= img.screenH)
        {
            ww = img.screenW;
            hh = img.screenH;

            left = (img.screenW - ww) / 2;
            top = (img.screenH - hh) / 2;
        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left, top, ww,hh);
        }
        else
        {
            left = (img.screenW - newW) / 2;
            top = (img.screenH - newH) / 2;
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, left, top, newW,newH);
        }
        break;
    case DFLIPIMGD:
        set_image();
        imlib_image_flip_diagonal ();
        set_blend();
        set_buffer();
        newH = img.set_newimg_h;
        newW = img.set_newimg_w;

        if(newW > img.screenH || newH > img.screenW )
        {
            std::cout<<"Too Big "<<newW<<"x"<<newH<<std::endl;
            std::cout<<"You're running "<<img.screenW<<"x"<<img.screenH<<std::endl;
            exit(1);
        }

        left = (img.screenW - newH) / 2;
        top = (img.screenH - newW) / 2;
        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w,left,top,newH,newW);
        break;
    case MOVEIMAGE:
        int newWidth, newHeight;
        aspect = (double) img.screenW / (double) w;
        if ( w >= img.screenW)
        {
            newWidth = ( w * aspect / 3);
            newHeight = ( h * aspect / 3);
        }
        else
        {
            newWidth = w;
            newHeight = h;
        }
            load_image_err();

    set_image();
    w = imlib_image_get_width();
    h = imlib_image_get_height();
    set_buffer();
        mvi.move();
        // for X
        if (mvi.getX() >= img.screenW ) {
            mvi.setPos(img.screenW, img.screenH);
            mvi.changeDirecton(DOWNLEFT);
            printf("ckX: x %d\n", mvi.getX() ); }
        if (mvi.getX() <= -1 && mvi.getY() <= -1) {
            mvi.changeDirecton(DOWNRIGHT);
            printf("ckX: x %d\n", mvi.getX() ); }

        if (mvi.getX() >= img.screenH )
        {
            mvi.randomDirection();
            printf("ckX x %d y %d\n", mvi.getX() ,mvi.getY() );
        }

        // for Y

        if (mvi.getY() >= img.screenH){
            mvi.changeDirecton(UPLEFT);
            printf("ckY y %d\n", mvi.getY() ); }
        if (mvi.getY() <= -1 ) {
            mvi.changeDirecton(LEFT);
            printf("ckY y %d\n", mvi.getY() ); }

        if (mvi.getY() >= img.screenH) {
            mvi.randomDirection();
            printf("ckY x %d  y %d\n",mvi.getX(), mvi.getY() ); }

        // source_x,source_y,source_width,source_height,
        // destination_x, destination_y, destination_width, destination_height
         imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, w, h, mvi.getX(), mvi.getY(), newWidth, newHeight);
        break;
    case SPACE_TILE:

        if (img.set_over_ride_system == 1)
            Flips_Spaced_Tile_Switch();

        if(img.flips_mode == 1)
            Flips_Spaced_Tile_Switch();

        switch (img.flip)
        {
            case 1:
                set_image();
                imlib_image_flip_vertical();
                set_blend();
                set_buffer();
                set_flip_tile(w,h,img.flip);
                break;
            case 2:
                set_image();
                imlib_image_flip_horizontal();
                set_blend();
                set_buffer();
                set_flip_tile(w,h,img.flip);
                break;
            case 3:
             //   std::cout<<"3 flip"<<std::endl;
                set_image();
                imlib_image_tile_vertical();
                set_blend();
                set_buffer();

                set_flip_tile(w,h,img.flip);
                break;
            case 4:
                set_image();
                imlib_image_tile_horizontal();
                set_blend();
                set_buffer();
                set_flip_tile(w,h,img.flip);
                break;
            case 5:
                set_image();
                imlib_image_tile();
                // imlib_image_flip_diagonal();
                set_blend();
                set_buffer();
                set_flip_tile(w,h,img.flip);

                break;
            case 6:
                set_image();
                imlib_image_flip_diagonal();
                set_blend();
                set_buffer();
                set_flip_tile(w,h,img.flip);
                break;

            default:
                set_image();
                set_blend();
                set_buffer();
              //  std::cout<<"enting load_image"<<" "<<img.flip<<std::endl;
              //  if (imgdata.image)
            //        std::cout<<"enting y load_image"<<" "<<img.flip<<std::endl;


                if ( h > (img.screenH / 3))
                {
                    newH = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
                    newW = (get_adjusted_by_aspect(get_aspect(h),w) / 3);
                }
                else
                {
                    newH = h;
                    newW = w;
                }
                top = (img.screenH - (int) (h * get_aspect(h))) / 2;
                left = (img.screenW - (int) (w * get_aspect(h))) / 2;


                for (; left > 0; left -= newW) {}
                    for (; top > 0; top -= newH) {}

                for (x = left; x < img.screenW; x += newW)
                {
                    for (y = top; y < img.screenH; y += newH)
                        imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w, x, y, newW / space_tile_gap((rand() % 3)) , newH / space_tile_gap((rand() % 3)));
                }
                break;
        } //end switch
        break; // for SPACE_TILE CASE
    default:
        break;

    } // end switch

    display_image();
}
void display_image()
{ //std::cout<<"in display_image"<<std::endl;
    if (imgdata.modifier != NULL) {
        imlib_context_set_color_modifier(imgdata.modifier);
        imlib_apply_color_modifier();
        imlib_free_color_modifier();
        imgdata.modifier = NULL;
      }

      imlib_render_image_on_drawable(0, 0);

     // imlib_free_image();
     imlib_free_image_and_decache ();
      imlib_free_color_range();

      if (setRootAtoms () == 0)
          fprintf (stderr, "Couldn't create atoms...\n");

      XKillClient (imgdata.display, AllTemporary);
      XSetCloseDownMode (imgdata.display, RetainTemporary);

      XSetWindowBackgroundPixmap (imgdata.display, RootWindow (imgdata.display, 0),imgdata.pixmap);
      XClearWindow (imgdata.display, RootWindow (imgdata.display, 0));

      XFlush (imgdata.display);
      XSync (imgdata.display, False);

      imlib_context_pop();
      imlib_context_free(imgdata.context);

     //  std::cout<<"leaving display image"<<"\n";

}
void setAlpha(void)
    {
        int o;

      if (img.alpha < 255) {
        // Create alpha-override mask
        imlib_image_set_has_alpha(1);
        Imlib_Color_Modifier modifier = imlib_create_color_modifier();
        imlib_context_set_color_modifier(modifier);

        DATA8 red[256], green[256], blue[256], alph[256];
        imlib_get_color_modifier_tables(red, green, blue, alph);
        for (o = 0; o < 256; o++)
          alph[o] = (DATA8) img.alpha;
        imlib_set_color_modifier_tables(red, green, blue, alph);

        imlib_apply_color_modifier();
        imlib_free_color_modifier();
      }
    }  // end setAlpha

// Adapted from fluxbox' bsetroot
int setRootAtoms (void)
{
    Atom atom_root, atom_eroot, type;
    unsigned char *data_root, *data_eroot;
    int format;
    unsigned long length, after;

    atom_root = XInternAtom (imgdata.display, "_XROOTMAP_ID", True);
    atom_eroot = XInternAtom (imgdata.display, "ESETROOT_PMAP_ID", True);

    // doing this to clean up after old background
    if (atom_root != None && atom_eroot != None)
    {
        XGetWindowProperty (imgdata.display, RootWindow (imgdata.display, 0),
                            atom_root, 0L, 1L, False, AnyPropertyType,
                            &type, &format, &length, &after, &data_root);

    if (type == XA_PIXMAP)
    {
        XGetWindowProperty (imgdata.display, RootWindow (imgdata.display, 0),
                            atom_eroot, 0L, 1L, False, AnyPropertyType,
                            &type, &format, &length, &after, &data_eroot);

    if (data_root && data_eroot && type == XA_PIXMAP &&
        *((Pixmap *) data_root) == *((Pixmap *) data_eroot))
    {
        XKillClient (imgdata.display, *((Pixmap *) data_root));
    }
  } // second if
} //first if

    atom_root = XInternAtom (imgdata.display, "_XROOTPMAP_ID", False);
    atom_eroot = XInternAtom (imgdata.display, "ESETROOT_PMAP_ID", False);

    if (atom_root == None || atom_eroot == None)
        return 0;

    // setting new background atoms
    XChangeProperty (imgdata.display, RootWindow (imgdata.display, 0),
                    atom_root, XA_PIXMAP, 32, PropModeReplace,
                    (unsigned char *) &imgdata.pixmap, 1);

    XChangeProperty (imgdata.display, RootWindow (imgdata.display, 0), atom_eroot,
                    XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &imgdata.pixmap,
                    1);


    return 1;
}


int parse_color(char *col, int *r, int *g, int *b, int *a)
{
    unsigned long cc, rr, gg, bb, aa;
    int len;
     len = strlen(col);

      if (( strlen(col) != 7) && (strlen(col) != 9))
        return 1;

    if (col[0] == '#')
    {
      /* #RRGGBBAA style */
      /* skip the '#' */
      col++;
      len = strlen(col);


    if (len == 8)
    {
        cc = (unsigned long) strtoul(col, NULL, 16);
        rr = (cc & 0xff000000) >> 24;
        gg = (cc & 0x00ff0000) >> 16;
        bb = (cc & 0x0000ff00) >> 8;
        aa = (cc & 0x000000ff);

    }
    else if (len == 6)
    {
        cc = (unsigned long) strtoul(col, NULL, 16);
        rr = (cc & 0xff0000) >> 16;
        gg = (cc & 0x00ff00) >> 8;
        bb = (cc & 0x0000ff);
        aa = 255;
    }
        *r = rr;
        *g = gg;
        *b = bb;
        *a = aa;

    }
    return 0;
}

double get_aspect(int x)
{

return (((double) img.screenH) / (double) x);

}
int get_adjusted_by_aspect(double aspect, int x)
{
    return (((int) (x * aspect)));
}

int get_adjusted_size(int h, int w, int wantedSize)
{
//(oginal height / oginal width) x wanted size = adjusted measument
    return (( (double)h / (double)w ) * (double)wantedSize);

}


int64_t int_or_ch(char *data)
{
    int len = 0, i;
    char *endptr;

    len = strlen(data);

    for ( i = 0; i < len ; i++)
    {// if not a digit return error code -1
        if ( isdigit(data[i]) == 0)
            return -1;
     }
     return strtol(data, &endptr, 10);
}


int findX(char *whereisX, unsigned int *wantW, unsigned int *wantH)
{

    const char ch = 'x';

    char *tok1, *tok2, *saveptr;
    char str1[1+strlen(whereisX)];
    strcpy(str1, whereisX);
    unsigned int giveW, giveH;

    if( strrchr(whereisX, ch) == NULL)
    {
        return 1;
    }
    else
    {
    tok1 = strtok_r(whereisX, "x", &saveptr);
    tok2 = strtok_r(NULL, "x", &saveptr);

    if ( tok2 == NULL)
    {
        return 1;
    }
     else
        {
            tok1 = strtok_r(str1, "x", &saveptr);
            tok2 = strtok_r(NULL, "x", &saveptr);

        if ( (giveW = int_or_ch(tok1) ) == -1)
            return 1;
        else
             *wantW = giveW;

        if ( (giveH = int_or_ch(tok2) ) == -1)
            return 1;
        else
            *wantH = giveH;
  return 0;
         }
    }
} //end findX


int findXChar(char *whereisX, char *wantW, char *wantH)
{

    const char ch = 'x';

    char *tok1, *tok2, *saveptr;
    char str1[1+strlen(whereisX)];
    strcpy(str1, whereisX);
    char giveW, giveH;

    if( strrchr(whereisX, ch) == NULL)
    {
        return 1;
    }
    else
    {
    wantW = strtok_r(whereisX, "x", &saveptr);
    wantH = strtok_r(NULL, "x", &saveptr);

    if ( wantH == NULL)
    {
        return 1;
    }
     else
        {
            wantW = strtok_r(str1, "x", &saveptr);
            wantH = strtok_r(NULL, "x", &saveptr);
            giveW = atoll(tok1);
            giveH = atoll(tok2);
        // assigning the results to the output
        //  giveW = tok1;
        //  giveH =  tok2;
           wantW = tok1;
           wantH = tok2;


 //   std::cout<<wantH<<" "<<wantW<<std::endl;

           return 0;
         }
    }
} //end findX


int seconds_or_minutes(char *what_is_it)
{
    const char sec = 's';
    const char min = 'm';
    char str1[1+strlen(what_is_it)];

    strcpy(str1, what_is_it);
    // if only s or m is present then return -1
    if ( ( ( strrchr(what_is_it, sec) != NULL ) || (strrchr(what_is_it, min) != NULL) ) && strlen(what_is_it) == 1)
    {
        return -1;
    }
    else if ( strrchr(what_is_it, sec) )
    {
        return (atoi( strtok(str1, "s") ));
    }
    else if( strrchr(what_is_it, min) )
    {
        return (atoi(strtok(str1,"m")) * 60);
    }//defaults to seconds

    return atoi(what_is_it);
}


void set_image()
{

    imlib_context_set_image(imgdata.image);
}
void set_buffer()
{
    imlib_context_set_image(imgdata.buffer);
}
void set_blend()
{
imlib_context_set_blend(1);
}
//space tiles

double space_tile_gap(int which_gap)
{   //std::cout<<"space_tile_gap  "<<which_gap<<std::endl;
    switch(which_gap)
    {
        case 0:
            return (1.011);
            break;
        case 1:
            return (1.1102);
            break;
        case 2:
            return (1.013);
            break;
        case 3:
            return (1.14);
            break;
        default:
            return (1.015);
            break;
    }
return (1.2);
}

//space tiles
void set_flip_tile(int w, int h, int flip)
{
    int newW,newH,x,y,top,left;
    // std::cout<<"newW"<<newW<<" newH "<<newH<<std::endl;
    if ( h > (img.screenH / 3))
    {
        newH = (get_adjusted_by_aspect(get_aspect(h),h) / 3);
        newW = (get_adjusted_by_aspect(get_aspect(h),w) / 3);

    }
    else
    {
        /*
        newH = h;
        newW = w;
        */
        ;
    }
    top = (img.screenH - (int) (h * get_aspect(h))) / 2;
    left = (img.screenW - (int) (w * get_aspect(h))) / 2;
    set_blend();
    set_buffer();
   // std::cout<<"set_flip_tile flip "<<flip<<std::endl;
    switch (flip)
    {
        case 1 ... 5:
             newW / space_tile_gap((rand() % 4));
             newH / space_tile_gap((rand() % 3));
           //  std::cout<<newW<<" "<<newH<<std::endl;

            for (; left > 0; left -= newW) {}
                for (; top > 0; top -= newH){}

            for (x = left; x < img.screenW; x += newW)
                for (y = top; y < img.screenH; y += newH)
                     imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w,
                     x,y, newW / space_tile_gap((rand() % 4)) ,
                     newH / space_tile_gap((rand() % 3)) );
            break;
        case 6:
            for (; left > 0; left -= newW)
            {}
                for (; top > 0; top -= newH)
                {}
            for (x = left; x < img.screenW; x += newW)

                for (y = top; y < img.screenH; y += newH)
            imlib_blend_image_onto_image (imgdata.image, 0, 0, 0, h,w,
                                            x,y, newW / space_tile_gap((rand() % 4)) ,
                                             newH / space_tile_gap((rand() % 3)) );
            break;
        default:
            break;
    }

}

void Flips_Spaced_Tile_Switch(void)
{
// give it a little more room to play setting it to N+1
 img.flip = (rand() % 7);

}

void BadFindX(char *bad)
{
    std::cout << "Badly "<<bad<<" formated size"<<std::endl;
}
void BeyondMaxColors(char *c)
{
    std::cout<< "Too Big a number, try a smaller one."<<c<<std::endl;
}

void set_oops_color(void)
{
    imgdata.display = XOpenDisplay(NULL);
    char oops1[8] = "#0000cc"; //blue
    char oops2[8] = "#33cc00"; //green
    char oops3[8] = "#ff0000"; //red
    if(!imgdata.display)
    return;

    img.screenW= DisplayWidth(imgdata.display, 0);
    img.screenH = DisplayHeight(imgdata.display, 0);

    if ( parse_color(oops1, &c.r, &c.g, &c.b, &c.a) == 1)
    {
        NoParse(oops1);
        exit(1);
    }

    setup_images();
    set_color();
    fill_rectangle();
    display_image();

    if ( parse_color(oops2, &c.r, &c.g, &c.b, &c.a) == 1)
    {
        NoParse(oops2);
        exit(1);
    }

    setup_images();
    set_color();
    fill_rectangle();
    display_image();

    if ( parse_color(oops3, &c.r, &c.g, &c.b, &c.a) == 1)
    {
        NoParse(oops3);
        exit(1);
    }

    setup_images();
    set_color();
    fill_rectangle();
    display_image();
}

bool is_file_exist(const char *fileName)
{
    std::ifstream infile(fileName);
    return infile.good();
}

void NoParse(char *clr)
{
    std::cout<<"Bad Color"<<clr<<""<<std::endl;
}

void Load_OOPs_Image()
{
    int w,h;
    setup_images();

  // imgdata.image = imlib_load_image( (const char *)OPPS_IMAGE );
    if ( is_file_exist( OPPS_IMAGE) )
    imgdata.image = imlib_load_image_immediately( (const char *) OPPS_IMAGE );
    else
    return;

    set_image();
    //set_blend();
    w = imlib_image_get_width();
    h = imlib_image_get_height();
    set_buffer();
    imlib_blend_image_onto_image (imgdata.image, 0, 0, 0,w, h, 0,0, img.screenW, img.screenH);
    display_image();

    if(imgdata.display)
        XCloseDisplay(imgdata.display);
}

void warning_message()
{
 std::cout<<"  *** WARNING WARNING WARNING ***"<<std::endl;
 std::cout<<"        Check your settings"<<std::endl;
 std::cout<<"        ERROR CODE ("<<getUserName()<<")"<<std::endl;
 std::cout<<"              man mh5000"<<std::endl;
 std::cout<<"   **** ERROR ERROR ERROR  ****"<<std::endl;
 exit(1);
}
char *getUserName()
{
  uid_t uid = geteuid();
  struct passwd *pw = getpwuid(uid);
  if (pw)
  {
    return pw->pw_name;
  }

  return NULL;
}

void get_randoms(void)
{
rc.r1 = (getRany(1,255));
rc.g1 = (getRany(0,255));
rc.b1 = (getRany(0,255));
rc.a1 = (getRany(0,255));


rc.r2 = (getRany(0,255));
rc.g2 = (getRany(0,255));
rc.b2 = (getRany(0,255));
rc.a2 = 255; // brighter colors

img.distance = (getRany(0,120));
img.angle = (getRany(0,360));
}

int rotate_angle(int d)
{
    if (img.rotate_angle_num > 360 )
    {
       img.rotate_angle_num = 10;
       d = 10;
    }
    return ( img.rotate_angle_num += d );
}

void set_display()
{
       imgdata.display = XOpenDisplay(NULL);
}
int get_readjusted_size(int h, int w, int wantedSize)
{
//(original height / original width) x wanted size = adjusted measurement
    return (( (double)h / (double)w ) * (double)wantedSize);

}
void fill_rectangle(void)
{
imlib_image_fill_rectangle(0, 0, img.screenW, img.screenH);
}
void set_color(void)
{
imlib_context_set_color(c.r, c.g, c.b, c.a);
}

void set_one_solid_color(void)
{
    if ( parse_color(img.solidColor, &c.r, &c.g, &c.b, &c.a) == 1)
    {
        NoParse(img.solidColor);
        exit(1);
    }
    set_color();
    fill_rectangle();

}
void set_two_colors(void)
{
 if (parse_color(img.color1, &c.r, &c.g, &c.b, &c.a) == 1)
{
    NoParse(img.color1);
    exit(1);
}
    imlib_context_set_color(c.r,c.g,c.b,c.a);
    imlib_add_color_to_color_range(img.distance);

 if (parse_color(img.color2, &c.r, &c.g, &c.b, &c.a) == 1)
{
    NoParse(img.color1);
    exit(1);
}
    imlib_context_set_color(c.r,c.b,c.b,c.a);
    imlib_add_color_to_color_range(img.distance);
    set_buffer();
    imlib_image_fill_color_range_rectangle (0, 0, img.screenW, img.screenH, img.angle);
}
void set_one_random_color(void)
{
    get_randoms();
    imlib_context_set_color(rc.a1,rc.g2,rc.b1,rc.a2);
    imlib_image_fill_rectangle(0, 0, img.screenW, img.screenH);
}
void set_two_random_colors(void)
{
    get_randoms();
    imlib_context_set_color(rc.r1, rc.b1, rc.g1, rc.a1);
    imlib_add_color_to_color_range(img.distance);

    imlib_context_set_color(rc.r2,rc.b2,rc.g2,rc.a2);
    get_randoms();
    imlib_add_color_to_color_range(img.distance);
    imlib_image_fill_color_range_rectangle (0, 0, img.screenW, img.screenH, img.angle);
}

void set_colors(void)
{
    int i = 0;

    if(img.angle_flag > 0)
        get_randoms();

    switch(img.color_flag)
    {
        case 1:
            set_one_solid_color();
            break;
        case 2:
            set_two_colors();
            break;
        case 3:
            set_one_random_color();
            break;
        case 4:
            for( i = 0; i < img.set_random_color_num; i++)
                set_two_random_colors();
            break;
        default:
            set_two_random_colors();
            break;

    }
}
int gettingWidthHeight(char *data, unsigned int *w, unsigned int *h)
{

    unsigned int width = 0, height = 0;
    int ret = 0;
    char trail = '\0';

    ret = sscanf(data,"%dx%d%c", &width,&height,&trail);
    if (ret == 2 && trail == '\0')
    {
        *w = width;
        *h = height;
        return 0;
    }
    else
        return -1;
}

int getPoints(char *data, unsigned int *x, unsigned int *y)
{
        unsigned int xfactor = 0, yfactor = 0;
        int ret = 0;
        char tail = '\0';
        ret = scanf(data, "%d,%d%c", &xfactor,&yfactor,&tail);
        if (ret == 2 && tail == '\0')
        {
            *x = xfactor;
            *y = yfactor;
            return 0;
        }
        else
        return -1;
}



void usage(char *argv[])
{
    std::cout<<"usage:\n";
    std::cout<<argv[0]<<" Version: "<<VERSION<<"\n";
    std::cout<<"Michael Heras (c) 2017"<<"\n\n";
    std::cout<<"Option for loading images. Either by path/Directory or file with path/filename"<<std::endl
    <<"-O"<<std::endl;
    std::cout<<"-c Center Image"<<std::endl<<"-c=<sizexsize> User selected image size"<<"\n"<<"-f Fullscreen"<<std::endl
    <<"-st=<1-7> Selection for spaced tiles"<<std::endl<<std::endl<<"Load Images via Directory"<<"\n";

    std::cout<<argv[0]<<" -st=3 -r -z 3m -O /path/to/directory"<<"\n"<<"Load Images via File\n";
    std::cout<<argv[0]<<" -c=600x800  -rc=35 -rd -ra -O /path/to/file/filename"<<"\n"
    <<"Load Single Image"<<"\n"<<argv[0]<<" -f -S /path/to/image/filename.jpg"<<"\n";
    std::cout<<"man mh5000 for more options\n"<<"\n";
}
