#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gd.h"
#include "gmp.h"

// Given a png image it will calculate a permutation index.

void m_rate_of_change
(
   mpz_t mRateOfChange,
   long  lColumn,
   long  lDepth
);

int range_from_colour_and_index
(
   mpz_t mRlo,
   mpz_t mRhi,
   int   iColour,
   int   iDepth,
   long  lIndex
);


int main
(
   int   iArgs    ,
   char *apsArgs[]
)
{
   FILE        *pFilePng  = NULL;
   gdImagePtr   gdIpIn    = NULL;
   char        *pcArgImg  = NULL;
   char        *pcArgX    = NULL;
   char        *pcArgY    = NULL;
   int          i         = 0;
   int          x         = 0;
   int          y         = 0;
   int          iColour   = 0;
   int          iIndex    = 0;
   mpz_t        mX;
   mpz_t        mY;
   mpz_t        mUnit;
   mpz_t        mUnit2;
   mpz_t        mPosX;
   mpz_t        mPosY;
   mpz_t        mStartX;
   mpz_t        mOffsetX;
   mpz_t        mRlo;
   mpz_t        mRhi;
   mpz_t        mRangeLo;
   mpz_t        mRangeHi;
   mpz_t        mDiff;
   mpz_t        mPerm;
   mpz_t        mN;
   mpz_t        mR;


   if (iArgs > 1)
   {
     for (i = 0; i < iArgs; i++)
     {
        if (0 == strncmp ("-i=", apsArgs[i], 3))         // -i image file
        {
           pcArgImg = apsArgs[i] + 3;
        }
        else if (0 == strncmp ("-x=", apsArgs[i], 3))        // -x x axis divisor
        {
           pcArgX = apsArgs[i] + 3;
           mpz_init (mX);
           gmp_sscanf(pcArgX,"%Zd", mX);
        }
        else if (0 == strncmp ("-y=", apsArgs[i], 3))        // -y y axis divisor
        {
           pcArgY = apsArgs[i] + 3;
           mpz_init (mY);
           gmp_sscanf(pcArgY, "%Zd", mY);
        }
     }
   }
   else
   {
      exit (printf ("USAGE: png_to_perm -i=imagefile.png [-x=xdivisor -y=ydivisor]\n"));
   }

   if (NULL == pcArgImg)
      exit (printf ("-i 'imagefile' was not specified\n"));


   // Load the image file.

	pFilePng = fopen (pcArgImg, "rb");
   if (NULL == pFilePng)
      exit (printf ("fopen(%s) failed", pcArgImg));

   gdIpIn = gdImageCreateFromPng (pFilePng);
   if (NULL == gdIpIn)
		exit (printf( "gdImageCreateFromPng() failed"));

	if (0 != fclose (pFilePng))
      exit (printf ("fclose() failed ()"));


//	printf ("File   :%s\n" , pcArgImg                   );
//	printf ("Width  :%d\n" , gdImageSX (gdIpIn)         );
//	printf ("Height :%d\n" , gdImageSY (gdIpIn)         );
//	printf ("Colours:%d\n" , gdImageColorsTotal (gdIpIn));

/*
   for (y = 0; y < gdImageSY (gdIpIn); y++)
   {
      for (x = 0; x < gdImageSX (gdIpIn); x++)
      {
         iColour = gdImageGetPixel (gdIpIn, x, y);
         printf ("%d,", iColour);
      }
      printf ("\n");
   }
   printf ("\n");
 */

   mpz_init (mRangeLo);
   mpz_init (mRangeHi);
   mpz_init (mRlo);
   mpz_init (mRhi);

   for (y = gdImageSY (gdIpIn)-1; y >= 0; y--)
   {
      for (x = gdImageSX (gdIpIn)-1; x >= 0; x--)
      {
         iColour = gdImageGetPixel (gdIpIn, x, y);
         //printf ("%d,", iColour);

         iIndex = (y * gdImageSX (gdIpIn)) + x;
         //printf ("%d,", iIndex);

         range_from_colour_and_index (mRlo, mRhi, iColour, gdImageColorsTotal (gdIpIn), iIndex);

         // rangelo = lo
         // rangehi = (hi - lo) + rangelo;

         mpz_add  (mRangeLo, mRangeLo, mRlo);
         mpz_init (mDiff);
         mpz_sub  (mDiff, mRhi, mRlo);
         mpz_add  (mRangeHi, mRangeLo, mDiff);

         // gmp_printf ("mRlo=%Zd mRhi=%Zd\n"        , mRlo, mRhi);
         // gmp_printf ("iIndex=%d mRangeLo=%Zd mRangeHi=%Zd\n", iIndex, mRangeLo, mRangeHi);

         mpz_clear (mDiff);
         mpz_clear (mRlo);
         mpz_clear (mRhi);
      }
      // printf ("\n");
   }

   // Output the rlo value - this should be the index.
   // In theory, rlo and rhi should be the same.

   //gmp_printf ("mRangeLo=%Zd\n", mRangeLo);

   gmp_printf ("%Zd", mRangeLo);

   if (NULL != pcArgX && NULL != pcArgY)
   {
      mpz_init (mPerm);
      mpz_init (mN);
      mpz_init (mR);

      mpz_set_ui (mPerm, 0);
      mpz_set_ui (mN   , gdImageColorsTotal (gdIpIn));
      mpz_set_ui (mR   , gdImageSY (gdIpIn) * gdImageSX (gdIpIn));
      // gmp_printf ("lNa=%Zd\n", lNa);
      // gmp_printf ("lNb=%Zd\n", lNb);
      // gmp_printf ("lRa=%Zd\n", lRa);


      mpz_pow_ui (mPerm, mN, mpz_get_ui(mR));
//      gmp_printf ("mN (Colours) = %Zd\n", mN);
//      gmp_printf ("lR (Pixels)  = %Zd\n", mR);
//      gmp_printf ("Permutations = %Zd\n", mPerm);

      // Work out the range of 1 unit in the X axis of a graph.
      // e.g If set the divisor to 100 this would return the number of keys in 1 percent.

      mpz_init   (mUnit);
      mpz_fdiv_q (mUnit, mPerm, mX);
      //gmp_printf ("X Axis:\nmX=%Zd\nmUnit=%Zd\n\n", mX, mUnit);

      // Work out how many units this key is.

      mpz_init (mPosX);
      mpz_fdiv_q (mPosX, mRangeLo, mUnit);  // This is the x axis post

      mpz_init (mStartX);
      mpz_init (mOffsetX);
      mpz_mul (mStartX, mUnit, mPosX);       // This is the start range of the mPosX
      mpz_sub (mOffsetX, mRangeLo, mStartX); // This is the offset of the x from the startx

      // Work out the range of 1 unit in the Y (which is a fraction of the X unit)

      mpz_init   (mUnit2);
      mpz_fdiv_q (mUnit2, mUnit, mY);  // This is the range of 1 y unit

      //gmp_printf ("Y Axis:\nmY=%Zd\nmUnit2=%Zd\n\n", mY, mUnit2);

      mpz_init (mPosY);
      mpz_fdiv_q (mPosY, mOffsetX, mUnit2);

//    gmp_printf ("mStartX=%Zd\n",mStartX);
//    gmp_printf ("mOffsetX=%Zd\n",mOffsetX);
      printf ("\n");

      gmp_printf ("mPosX=%Zd\n",mPosX);
      gmp_printf ("mPosY=%Zd\n",mPosY);

      mpz_clear (mX);
      mpz_clear (mY);
      mpz_clear (mUnit);
      mpz_clear (mUnit2);
      mpz_clear (mPosX);
      mpz_clear (mPosY);
      mpz_clear (mOffsetX);
      mpz_clear (mStartX);
   }

/*
   // Save the image

   pFile = fopen ("out.png", "wb");
   if (NULL == pFile)
      return (printf("fopen() failed"));

   gdImagePng (gdIpIn, pFile);
   //   gdImageJpeg (gdIp, pFile, -1);

   if (0 != fclose (pFile))
      return (printf("fclose() failed"));
*/


	gdImageDestroy (gdIpIn); // Returns void.

   return (0);
}


int range_from_colour_and_index
(
   mpz_t mRlo,
   mpz_t mRhi,
   int   iColour,
   int   iDepth,
   long  lIndex
)
{
   mpz_t mROC;

   mpz_init (mRlo);
   mpz_init (mRhi);
   mpz_init (mROC);

   // lo = color * (rate of change - 1)
   // hi = lo + (rate of change - 1)

   m_rate_of_change (mROC, lIndex, iDepth);
   mpz_sub_ui (mROC, mROC, 1);
   mpz_mul_ui (mRlo, mROC, iColour);

   mpz_set (mRhi, mRlo);
   mpz_add (mRhi, mRhi, mROC);

   mpz_clear (mROC);

   return (0);
}



void m_rate_of_change
(
   mpz_t mRateOfChange,
   long  lColumn,
   long  lDepth
)
{
   mpz_t mDepth;

   mpz_init (mRateOfChange);
   mpz_init (mDepth);

   mpz_set_ui (mDepth, lDepth);
   mpz_pow_ui (mRateOfChange, mDepth, lColumn);
   mpz_add_ui (mRateOfChange, mRateOfChange, 1L);
   //gmp_printf ("column=%ld, Rate of change=%Zd\n", lColumn, mRateOfChange);

   mpz_clear (mDepth);
}
