#include"pns.h"
#include"codegen.h"


int verb = 3;

int inline is_verbose() { return verb; }

int main() {
  int i;

  /* Declaring pn objects */

  pns pn_p, pn_s, pn_s2, pn, pn2, pn3;
  process pr1, pr2, pr3, *apr[2];


  /* Petri nets can be initialized using the incidence matrix */

  /* This will be used for the incidence matrix of one pn */

  int Dp[] = {  1,  1, -1,  1,  0,  0,\
	        0,  0,  1,  0, -1,  0,\
	        0, -1,  1,  0,  0, -1,\
               -1,  0,  0,  0,  1,  0,\
	        0,  0,  0, -1,  0,  1};

  int mp[] = { 1, 1, 1, 1, 1}; /* The initial marking */

  /* These will be used for the input and output matrices of another pn */

  int Is[] = {  0,  1,  0,  0,\
		0,  0,  1,  0,\
		0,  0,  0,  1,\
		1,  0,  0,  0};

  int Os[] = {  0,  0,  1,  0,\
		0,  0,  0,  1,\
		1,  0,  0,  0,\
		0,  1,  0,  0};

  int ms[] = {0, 0, 1, 1}; /* The initial marking */

  struct placelist *plist;
  arcs* alist;
  char *str;

  /* Here is how the pn objects are created */

  /* The following creates a pn of 5 places, 6 transitions, incidence 
     matrix Dp, and initial marking mp */
  pn_p = createpn("pnum tnum D m0", 5, 6, Dp, mp); 

  /* Here the input and output matrices are used to initialize the pn */
  pn_s = createpn("pnum tnum I O m0", 4, 4, Is, Os, ms);

  /* This creates a pn object without transition arcs */
  pn = createpn("pnum tnum", 3, 5);

  int m0pn[] = {1, 0, 0};
  updatepn(&pn, "m0", m0pn);

  // Let's create the following PN:
  //             
  //            t2
  //     -------|<---- 
  //    | p0    p1    |p2
  //    ->O->|->O->|->O<--
  //      |  t0 |  t1     |
  //      |     |         |
  //      |     V         |
  //      |    --- t3     |
  //      |               |
  //       ------>|-------
  //               t4

  /* GetMatrixEl and SetMatrixEl can be used to read or write the elements
     of a matrix. */

  /* For instance, arcs could be added by changing the value of the input 
     and output matrices of the pn */

  SetMatrixEl(&pn.out, 0, 0, 1); /* add arc from p0 to t0 of weight 1 */
  SetMatrixEl(&pn.out, 0, 4, 1); /* add arc from p0 to t4 of weight 1 */
  SetMatrixEl(&pn.in, 0, 2, 1);

  SetMatrixEl(&pn.out, 1, 1, 1); 
  SetMatrixEl(&pn.out, 1, 3, 1); 
  SetMatrixEl(&pn.in, 1, 0, 1); 

  SetMatrixEl(&pn.out, 2, 2, 1); 
  SetMatrixEl(&pn.in, 2, 1, 1); 
  SetMatrixEl(&pn.in, 2, 4, 1); 

  int labls[] = {-1, -2, -3, -4, -5};
  updatepn(&pn, "labels", labls);

  // Let's create one more PN:
  //
  //      p0    p1    
  //   |->O->|->O->|
  //   t2    t0    t1     
  //

  pn3= createpn("pnum tnum", 2, 3);
  int labl2[] = {-1, -7, -5};

  SetMatrixEl(&pn3.out, 0, 0, 1); /* add arc from p0 to t0 of weight 1 */
  SetMatrixEl(&pn3.in, 0, 2, 1);

  SetMatrixEl(&pn3.out, 1, 1, 1); 
  SetMatrixEl(&pn3.in, 1, 0, 1); 

  updatepn(&pn3, "labels", labl2);

  /* For instance, to check whether there is an arc from t1 to p2: */
  i = GetMatrixEl(&pn.in, 2, 1);
  if(i)
    fprintf(stderr, "\nThe arc (t1, p2) has the weight %d.\n", i);
  else
    fprintf(stderr, "\nThere is no arc from t1 to p2.\n");

  /* To display in text format a Petri net object use displaypn */

  fprintf(stderr, "\n** PN_P *************************************\n");
  displaypn(pn_p, stderr); /* displays pn_p */
  fprintf(stderr, "\n** PN_S *************************************\n");
  displaypn(pn_s, stderr); /* displays pn_s */
  fprintf(stderr, "\n** PN *************************************\n");
  displaypn(pn, stderr); /* displays pn */

  /* Properties of the pn objects can be set or changed with updatepn */

  updatepn(&pn, "place_name", 0, "start_p");
  /* The line above associates the name "start_p" with the place 0 */

  updatepn(&pn, "trans_name", 0, "tr0");
  /* The line above associates the name "tr0" with the transition 0 */

  updatepn(&pn, "select", 1, "f1(u)"); /*select function 'f1' for place 1*/

  updatepn(&pn, "segment", 0, "u++; printf(\"\\nPN: State 0 u = %d\", u);\ndelay(1);"); 
  updatepn(&pn, "segment", 1, "printf(\"\\nPN: State 1\");\ndelay(1);");
  updatepn(&pn, "segment", 2, "printf(\"\\nPN: State 2\");\ndelay(1);");

  updatepn(&pn3, "segment", 0, "u++; printf(\"\\nPN3: State 0 u = %d\", u);\ndelay(2);"); 
  updatepn(&pn3, "segment", 1, "printf(\"\\nPN3: State 1\");\ndelay(2);");

  /* Text transmitted by means of createpn/updatepn is copied to the 
     corresponding items of the pns object; thus it should be 
     deallocated, when applicable. For instance: */

  //str = tcalloc(strlen("f1(i, j);")+1, sizeof(char));
  //strcpy(str, "f1(i, j);");
  //updatepn(&pn, "segment", 1, str);
  ///* Now, str may be freed, since its content has been copied */
  // free(str);

  /* Flags are set as follows. */

  updatepn(&pn, "unobservable nondeterministic", 0, 1);
  /* marks transition 0 unobservable and place 1 as nondeterministic */

  updatepn(&pn, "live uncontrollable uncontrollable", 0, 0, 2);
  /* The line above sets the "live" and "uncontrollable" flags of 
     transition 0 and the uncontrollable flag of transition 2 */

  /* To create a copy */

  pn2 = copypn(&pn);



  /* Arcs are added similarly (using createpn or updatepn). Here is
     an example. */

  plist = tmalloc(sizeof(struct placelist));
  plist->place = 1;
  plist->next = tmalloc(sizeof(*plist));
  plist->next->place = 2;
  plist->next->next = 0;

  alist = tmalloc(sizeof(arcs));
  alist->in_place = 0;
  alist->out_places = plist;
  alist->condition = tcalloc(strlen("j == i || z == 0.1")+1, sizeof(char));
  strcpy(alist->condition, "j == i || z == 0.1");
  alist->next = 0;

  updatepn(&pn, "arcs", 0, alist); /* arc list associated with transition 0 */ 

  /* The line above updates the arc_list item of the pns object as well as the 
     input & output matrices. */ 

  /* Note the absence of the lines of code deallocating alist. The object alist is
     placed in the pns object, it is not copied. Thus, alist is deallocated when 
     the pns object is deallocated with the function deallocpn. */ 


  TrData **TInf;

  // Let's create also some processes

  asprintf(&(pr1.name), "type_one"); asprintf(&(pr2.name), "PN3");
  pr1.instance = "pr1";  pr2.instance = "pr2";
  pr1.thread = 0; pr2.thread = 1;
  pr1.pn = &pn2; pr2.pn = &pn3;
  asprintf(&(pr1.build), "gcc -g -o $$$.exe $$$.c"); 
  pr2.build = 0;
  // pr2.build = "make -f pn3.mak";
  pr1.include = "#include<stdio.h>\nint pr1_state = 0, i, j, u = 0;\n\n\
void delay(int n) {\n  time_t a, b;\n\
  for(time(&a), time(&b); a + n > b; time(&b));\n}\n\nint f1(int z) {\n\
  if(u > 5) {\n\
    ___TR[0].no_output = 1;\n\
    ___TR[0].label = -4;\n\
    ___TR[0].trans = 3;\n\
  }\n\
  else {\n\
    ___TR[0].no_output = 0;\n\
    ___TR[0].label = -2;\n\
    ___TR[0].trans = 1;\n\
    ___TR[0].place = 2;\n\
  }\n\
  return 1;\n\
}\n";
  pr2.include = "#include<stdio.h>\nint pr1_state = 0, i, j, u = 0;\n\n\
void delay(int n) {\n  time_t a, b;\n\
  for(time(&a), time(&b); a + n > b; time(&b));\n}\n\n";

  pr1.type = 0; pr1.start = 1; pr2.type = 1; pr2.start = 0;
  apr[0] = &pr1;
  apr[1] = &pr2;

  TInf = calloc(sizeof(TrData*), 2);
  TInf[0] = calloc(sizeof(TrData), pn2.tnum);
  TInf[1] = calloc(sizeof(TrData), pn3.tnum);

  // int labls[] = {-1, -2, -3, -4, -5};
  // int labl2[] = {-1, -7, -5};

  struct synclist *sn1;
  struct sync_element *se;

  sn1 = calloc(2, sizeof(*sn1));
  se = calloc(10, sizeof(*se));

  sn1[0].next = sn1+1; sn1->s = &se[0]; 
  se[0].prtype = 0; se[0].n = 1;
  int t1[] = {0}, w1[] = {1};
  se[0].t = t1; se[0].w = w1; se[0].next = &se[1];
  se[1].prtype = 1; se[1].t = t1; se[1].w = w1; se[1].n = 1; 
  sn1[1].s = &se[2];
  int t2[] = {4};
  se[2].prtype = 0; se[2].t = t2; se[2].w = w1; se[2].n = 1;
  sn1[1].o = &se[3]; se[3].n = 1;
  int t3[] = {2}, p1[] = {0};
  se[3].prtype = 1; se[3].t = t3; se[3].w = w1; se[3].p = p1;

  //compileProcessArray(apr, 2, TInf);
  //fprintf(stderr, "\nNow generating the supervisor ...");
  //compileSupervisor(&pn2, "spr", apr, 2, TInf, sn1, 0);
	
  CodeGenerator(&pn2, "spr", apr, 2, sn1, TInf, 0);
	       
  for(i = 0; i < 2; i++)
    free(TInf[i]);
  free(TInf);
  free(se); free(sn1); free(pr1.name); free(pr2.name);
  /* To deallocate a pn object use deallocpn */

  deallocpn(&pn_p); 
  deallocpn(&pn_s); 
  deallocpn(&pn); 
  deallocpn(&pn2);

  return 0;
}
