#include "atlas_taffinity.h"
#include "atlas_misc.h"
#include "assert.h"

#if defined(__MINGW32__) || defined(__MINGW64__)

int slashdrivesub(char *ln)
/*
 * replaces \\c\ with c:\, returns change in string length
 * this version required for older cygwins
 */
{
   char *sp, *lp=ln, ctmp;
   int nrep=0;
   do
   {
      sp = strstr(lp, "\\\\");
      if (sp && strlen(sp) > 3)
      {
         if (sp[2] == 'a' || sp[2] == 'b' || sp[2] == 'c' || sp[2] == 'd' ||
             sp[2] == 'e' || sp[2] == 'f' || sp[2] == 'g' || sp[2] == 'h')
         {
            if (sp[3] == '\\')
            {
               ctmp = sp[2];
               sp[0] = sp[2];
               sp[1] = ':';
               sp[2] = '\\';
               for (lp=sp+3; *lp = lp[1]; lp++);
               lp = sp + 3;
               nrep++;
            }
            else lp = sp + 2;
         }
         else lp = sp + 2;
      }
      else lp = sp + 2;
   }
   while (sp);
   return(-nrep);
}

int cygdrivesub(char *ln)
/*
 * replaces \cygdrive\c\ with c:\, returns change in string length
 * this version works cygnus version 1.1.0
 */
{
   char *sp;
   int i=0;

   while(sp = strstr(ln, "\\cygdrive\\"))
   {
      i++;
      sp[0] = sp[10];
      sp[1] = ':';
      sp[2] = '\\';
      sp += 3;
      while (*sp = sp[9]) sp++;
   }
   return( slashdrivesub(ln) - (i*9) );
}

void slashsub(char *ln)
/*
 * changes forward slash of unix to backslash of windoze
 */
{
   int i;
   for (i=0; ln[i]; i++) if (ln[i] == '/') ln[i] = '\\';
}

#endif


void PrintUsage(char *nam)
{
   fprintf(stderr, "\nUSAGE: %s [-o <outfile>]\n", nam);
   exit(-1);
}

FILE *GetFlags(int nargs, char **args)
{
   int i;
   FILE *fpout=stdout;

   for (i=1; i < nargs; i++)
   {
      if (args[i][0] != '-') PrintUsage(args[0]);
      switch(args[i][1])
      {
      case 'o':
         #if defined(__MINGW32__) || defined(__MINGW64__)
         {
            char *wp;
            wp = malloc(sizeof(char)*(strlen(args[++i])+1));;
            strcpy(wp, args[i]);
            slashsub(wp);
            cygdrivesub(wp);
            fpout = fopen(wp, "w");
            free(wp);
         }
         #else
            fpout = fopen(args[++i], "w");
         #endif
         assert(fpout);
         break;
      default:
         PrintUsage(args[0]);
      }
   }
   return(fpout);
}

void getLaunchOrder(int P, int *lo)
{
   int i, j, k, stop, dest;

   for (i=0; (1<<i) < P; i++)
   lo[0] = 0;
   k = 1;
   for (i--; i >= 0; i--)
   {
      stop = k;
      for (j=0; j < stop; j++)
      {
         dest = lo[j] + (1<<i);
         if (dest < P)
            lo[k++] = dest;
         if (k == P)
            return;
      }
   }
}

int main(int nargs, char **args)
{
   FILE *fpout;
   int i, j, k, P;
   int *lo;
   fpout = GetFlags(nargs, args);

   fprintf(fpout, "  /* This file generated by %s */\n", __FILE__);
   fprintf(fpout, "#ifndef ATLAS_NTHREADS_H\n   #define ATLAS_NTHREADS_H\n\n");
   #if !defined(ATL_PAFF_WIN64) && !defined(ATL_PAFF_WIN)
      fprintf(fpout, "#include \"pthread.h\"\n");
   #endif
   #if ATL_NCPU != 0
      P = ATL_NCPU;
   #elif defined(ATL_AFF_NUMID)
      P = ATL_AFF_NUMID;
   #else
      P = 4;
   #endif
   #if defined(ATL_AFF_NUMID)
      #if ATL_NCPU > ATL_AFF_NUMID
         fprintf(fpout,
         "/*\n * I should have tested if NTHREADS = %d(NCPU) or %d(NAFFIDs)\n");
         fprintf(fpout, " * is better.  For now, assuming %d\n */", ATL_NCPU);
      #endif
   #endif
   fprintf(fpout, "   #define ATL_NTHREADS %d\n", P);
   for (i=0; (1<<i) < P; i++);
   fprintf(fpout, "   #define ATL_NTHRPOW2 %d\n", i);
   lo = malloc(P*sizeof(int));
   getLaunchOrder(P, lo);
   fprintf(fpout, "   #ifdef ATL_LAUNCHORDER\n");
   fprintf(fpout, "       static int ATL_launchorder[%d] = {0", P);
   for (i=1; i < P; i++)
      fprintf(fpout, ",%d", lo[i]);
   fprintf(fpout, "};\n   #endif\n");
   #if defined(ATL_AFF_NUMID) && !defined(ATL_RANK_IS_PROCESSORID)
      fprintf(fpout, "   #if defined(ATL_RANK2ID)\n");
      fprintf(fpout, "       static int ATL_rank2ID[%d] = {%d",
              P, ATL_affinityIDs[0]);
      for (i=1; i < P; i++)
         fprintf(fpout, ",%d", ATL_affinityIDs[i%ATL_AFF_NUMID]);
      fprintf(fpout, "};\n   #endif\n");
   #endif
   fprintf(fpout, "\n#endif\n");
   fclose(fpout);
   return(0);
}
