#!/bin/bash
#
# @file:
#   gen_factoring.sh
#
# @description:
#   Generate the factoring device
# without the master set/working set paradigm.
# This script emits C++ code for factoring
# 32/64 bit integers.
#
# @author:
#   Roger G. Doss
#

M=4096;
COUNT=0;
OUTPUT="resolution.C"
DATE="`date`"
if [ -e $OUTPUT ]
then
    rm -f $OUTPUT
fi
#
# Output the preamble.
#
printf "\t/* Copyright (C) Roger G. Doss.  All rights reserved. */\n" >> $OUTPUT
printf "\t/* Code generated on $DATE */\n" >> $OUTPUT
printf "\t#include \n" >> $OUTPUT
printf "\t#include \n" >> $OUTPUT
printf "\t#include \n" >> $OUTPUT
printf "\tusing namespace std;\n" >> $OUTPUT
printf "\ttypedef long long long_t;\n" >> $OUTPUT
printf "\tclass res {\n" >> $OUTPUT
printf "\tpublic: res(long_t _p, long_t _q) { p = _p; q = _q; }\n" >> $OUTPUT
printf "\tpublic: long_t p,q;\n" >> $OUTPUT
printf "\t};\n" >> $OUTPUT
printf "\tclass resolution {\n" >> $OUTPUT
printf "\tpublic: resolution(long_t n)\n" >> $OUTPUT
printf "\t{\n" >> $OUTPUT
printf "      list *l  = new list();\n">> $OUTPUT
printf "      res  *r  = new res(0,0),\n">> $OUTPUT
printf "          *tmp = new res(0,0),\n">> $OUTPUT
printf "         *tmp1 = new res(0,0);\n">> $OUTPUT
printf "      long_t p;\n">> $OUTPUT
printf "      __do_factor(n,r);\n">> $OUTPUT
printf "      l->push_back(r);\n">> $OUTPUT
printf "      while(l->size()) {\n">> $OUTPUT
printf "         res *r = l->front();\n">> $OUTPUT
printf "         l->pop_front();\n">> $OUTPUT
printf "         if(r->p == 1 || r->q == 1) {\n">> $OUTPUT
printf "            if(r->p != 1) p = r->p;\n">> $OUTPUT
printf "            if(r->q != 1) p = r->q;\n">> $OUTPUT
printf "            cout << \"p: \" << p << endl;\n">> $OUTPUT
printf "            continue;\n">> $OUTPUT
printf "         }\n">> $OUTPUT
printf "         __do_factor(r->p,tmp);\n">> $OUTPUT
printf "         __do_factor(r->q,tmp1);\n">> $OUTPUT
printf "         l->push_back(new res(tmp->p, tmp->q));\n">> $OUTPUT
printf "         l->push_back(new res(tmp1->p, tmp1->q));\n">> $OUTPUT
printf "      }\n">> $OUTPUT
printf "\t}\n" >> $OUTPUT
printf "\tvoid __do_factor(long_t n, res *r)\n" >> $OUTPUT
printf "\t{\n" >> $OUTPUT
printf "      if(n == 1 || n == 0) { r->p = 1; r->q = n; return; }\n" >> $OUTPUT
printf "      if((n %% 2) == 0) {\n" >> $OUTPUT
printf "         r->p = 2; r->q = n/2;\n" >> $OUTPUT
printf "         return;\n" >> $OUTPUT
printf "      }\n" >> $OUTPUT
printf "      long_t bound = (long_t)ceil(sqrt((long double)n));\n" >> $OUTPUT
printf "      int m = $M;\n" >> $OUTPUT
printf "      long_t limit = (long_t)ceil((long double)bound/m);\n" >> $OUTPUT
printf "      if(limit == 0) { limit = 1; }\n" >> $OUTPUT
printf "      long_t *k = new long_t[m];\n" >> $OUTPUT
printf "      k[0]=3;\n" >> $OUTPUT
printf "      for(int i = 1; i < m; i++) {\n" >> $OUTPUT
printf "        k[i]=k[i-1]+limit;\n" >> $OUTPUT
printf "        if((k[i] %% 2) == 0) { k[i]++; }\n" >> $OUTPUT
printf "      }\n" >> $OUTPUT
printf "      long_t count = 0;\n\t\tr->p = 0;\n\t\tr->q = 0;\n" >> $OUTPUT
printf "      limit /= 2; limit++;\n" >> $OUTPUT
printf "      while(count++ < limit) {\n" >> $OUTPUT
printf "\n" >> $OUTPUT
#
# Generate the test branches up to M.
#
while [ $M != 0 ]
do
    printf "        if((n %% k[$COUNT] ) == 0) {\n" >> $OUTPUT
    printf "            r->p = n/k[$COUNT]; r->q = k[$COUNT];\n" >> $OUTPUT
    printf "            break;\n" >> $OUTPUT
    printf "        }\n" >> $OUTPUT
    printf "        k[$COUNT] += 2;\n" >> $OUTPUT
    ((COUNT=$COUNT + 1));
    ((M=$M - 1));
done
#
# Terminate the device.
#
printf "      }\n" >> $OUTPUT
printf "      if(r->p == 0 && r->q == 0) {\n" >> $OUTPUT
printf "        r->p = 1; r->q = n;\n" >> $OUTPUT
printf "      }\n" >> $OUTPUT
printf "   }\n" >> $OUTPUT
printf "  };\n" >> $OUTPUT
#
# Output main.
#
printf "    int main(int argc, char **argv)\n" >> $OUTPUT
printf "    {\n" >> $OUTPUT
printf "            if(argc != 2) { cerr << \"syntax: resolution number\" << endl; return 1; }\n" >> $OUTPUT
printf "            long_t i = strtoull(argv[1],NULL,10);\n" >> $OUTPUT
printf "            resolution *_1 = new resolution(i);\n" >> $OUTPUT
printf "            return 0;\n" >> $OUTPUT
printf "    }\n" >> $OUTPUT
#
# EOF
#