/*
*********************************************************************
                                                                   
INPFILE.C -- Save Input Function for EPANET Program                
                                                                    
VERSION:    2.00                                               
DATE:       5/8/00
            3/1/01
            11/19/01                                          
            6/24/02
            8/15/07    (2.00.11)
            2/14/08    (2.00.12)
AUTHOR:     L. Rossman
            US EPA - NRMRL
                                                                    
This module contains the function saveinpfile() which saves the
data describing a piping network to a file in EPANET's text format.                                    
                                                                    
********************************************************************
*/

#include <stdio.h>
#include <string.h>
#ifndef __APPLE__
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <math.h>
#include "hash.h"    
#include "text.h"
#include "types.h"
#include "funcs.h"
#define  EXTERN  extern
#include "vars.h"

/* Defined in enumstxt.h in EPANET.C */
extern char *LinkTxt[];
extern char *FormTxt[];
extern char *StatTxt[];
extern char *FlowUnitsTxt[];
extern char *PressUnitsTxt[];
extern char *ControlTxt[];
extern char *SourceTxt[];
extern char *MixTxt[];
extern char *TstatTxt[];
extern char *RptFlagTxt[];
extern char *SectTxt[];


void  saveauxdata(FILE *f)                                                     //(2.00.12 - LR)
/*
------------------------------------------------------------
  Writes auxilary data from original input file to new file.
------------------------------------------------------------
*/
{
   int   sect,newsect;
   char  *tok; 
   char  line[MAXLINE+1];
   char  s[MAXLINE+1];

   sect = -1;
   rewind(InFile);
   while (fgets(line,MAXLINE,InFile) != NULL)
   {
   /* Check if line begins with a new section heading */
      strcpy(s,line);
      tok = strtok(s,SEPSTR);
      if (tok != NULL && *tok == '[')
      {
         newsect = findmatch(tok,SectTxt);
         if (newsect >= 0)
         {
            sect = newsect;
            if (sect == _END) break;
            switch(sect)
            {
               case _RULES:
               case _COORDS: if (Coordflag == FALSE)
                             {
                                 fprintf(f, "%s", line);
                             }
                             break;
               case _VERTICES:
               case _LABELS:
               case _BACKDROP:
               case _TAGS: fprintf(f, "%s", line);                             //(2.00.12 - LR)
            }
            continue;
         }
         else continue;
      }

   /* Write lines appearing in the section to file */
      switch(sect)
      {
          case _RULES:
               case _COORDS: if (Coordflag == FALSE)
                             {
                                 fprintf(f, "%s", line);
                             }
                             break;
          case _VERTICES:
          case _LABELS:
          case _BACKDROP:
          case _TAGS: fprintf(f, "%s", line);                                  //(2.00.12 - LR)
      }
   }
}


////  This function was heavily modified.  ////                                //(2.00.12 - LR)

int  saveinpfile(char *fname)
/*
-------------------------------------------------
  Writes network data to text file.
-------------------------------------------------
*/
{
   int     i,j,n;
   double  d,kc,ke,km,ucf;
   char    s[MAXLINE+1], s1[MAXLINE+1], s2[MAXLINE+1];
   Pdemand demand;
   Psource source;
   FILE    *f;

/* Open the new text file */

   if ((f = fopen(fname,"wt")) == NULL) return(308);

/* Write [TITLE] section */

   fprintf(f,"[TITLE]");
   for (i=0; i<3; i++)
   {
      if (strlen(Title[i]) > 0) fprintf(f,"\n%s",Title[i]);
   }

/* Write [JUNCTIONS] section */
/* (Leave demands for [DEMANDS] section) */

   fprintf(f,"\n\n[JUNCTIONS]");
   for (i=1; i<=Njuncs; i++)
      fprintf(f,"\n %-31s %12.4f", Node[i].ID, Node[i].El*Ucf[ELEV]);

/* Write [RESERVOIRS] section */

   fprintf(f,"\n\n[RESERVOIRS]");
   for (i=1; i<=Ntanks; i++)
   {
      if (Tank[i].A == 0.0)
      {
         n = Tank[i].Node;
         sprintf(s," %-31s %12.4f",Node[n].ID, Node[n].El*Ucf[ELEV]);
         if ((j = Tank[i].Pat) > 0)
            sprintf(s1," %-31s",Pattern[j].ID);
         else
            strcpy(s1,"");
         fprintf(f, "\n%s %s", s,s1);
      }
   }

/* Write [TANKS] section */

   fprintf(f,"\n\n[TANKS]");
   for (i=1; i<=Ntanks; i++)
   {
      if (Tank[i].A > 0.0)
      {
         n = Tank[i].Node;
         sprintf(s," %-31s %12.4f %12.4f %12.4f %12.4f %12.4f %12.4f",
            Node[n].ID,
            Node[n].El*Ucf[ELEV],
            (Tank[i].H0 - Node[n].El)*Ucf[ELEV],
            (Tank[i].Hmin - Node[n].El)*Ucf[ELEV],
            (Tank[i].Hmax - Node[n].El)*Ucf[ELEV],
            sqrt(4.0*Tank[i].A/PI)*Ucf[ELEV],
            Tank[i].Vmin*SQR(Ucf[ELEV])*Ucf[ELEV]);
         if ((j = Tank[i].Vcurve) > 0)
            sprintf(s1,"%-31s",Curve[j].ID);
         else
            strcpy(s1,"");
         fprintf(f, "\n%s %s", s,s1);
      }
   }

/* Write [PIPES] section */

   fprintf(f,"\n\n[PIPES]");
   for (i=1; i<=Nlinks; i++)
   {
      if (Link[i].Type <= PIPE)
      {
         d = Link[i].Diam;
         kc = Link[i].Kc;
         if (Formflag == DW) kc = kc*Ucf[ELEV]*1000.0;
         km = Link[i].Km*SQR(d)*SQR(d)/0.02517;
         sprintf(s," %-31s %-31s %-31s %12.4f %12.4f",
            Link[i].ID,
            Node[Link[i].N1].ID,
            Node[Link[i].N2].ID,
            Link[i].Len*Ucf[LENGTH],
            d*Ucf[DIAM]);
         if (Formflag == DW) sprintf(s1, "%12.4f %12.4f", kc, km);
         else                sprintf(s1, "%12.4f %12.4f", kc, km);
         if (Link[i].Type == CV) sprintf(s2,"CV");
         else if (Link[i].Stat == CLOSED) sprintf(s2,"CLOSED");
         else strcpy(s2,"");
         fprintf(f,"\n%s %s %s",s,s1,s2);
      }
   }

/* Write [PUMPS] section */

   fprintf(f, "\n\n[PUMPS]");
   for (i=1; i<=Npumps; i++)
   {
      n = Pump[i].Link;
      sprintf(s," %-31s %-31s %-31s",
         Link[n].ID,
         Node[Link[n].N1].ID,
         Node[Link[n].N2].ID);

   /* Pump has constant power */
      if (Pump[i].Ptype == CONST_HP)
         sprintf(s1, "  POWER %.4f", Link[n].Km);

   /* Pump has a head curve */
      else if ((j = Pump[i].Hcurve) > 0)
         sprintf(s1, "  HEAD %s", Curve[j].ID);

   /* Old format used for pump curve */
      else
      {
         fprintf(f, "\n%s %12.4f %12.4f %12.4f          0.0 %12.4f",s,
                 -Pump[i].H0*Ucf[HEAD],
                 (-Pump[i].H0 - Pump[i].R*pow(Pump[i].Q0,Pump[i].N))*Ucf[HEAD],
                 Pump[i].Q0*Ucf[FLOW],
                 Pump[i].Qmax*Ucf[FLOW]);
         continue;
      }
      strcat(s,s1);

      if ((j = Pump[i].Upat) > 0)
         sprintf(s1,"   PATTERN  %s",Pattern[j].ID);
      else strcpy(s1,"");
      strcat(s,s1);

      if (Link[n].Kc != 1.0)
         sprintf(s1, "  SPEED %.4f", Link[n].Kc);
      else strcpy(s1,"");
      strcat(s,s1);

      fprintf(f,"\n%s",s);
   }

/* Write [VALVES] section */

   fprintf(f, "\n\n[VALVES]");
   for (i=1; i<=Nvalves; i++)
   {
      n = Valve[i].Link;
      d = Link[n].Diam;
      kc = Link[n].Kc;
      if (kc == MISSING) kc = 0.0;
      switch (Link[n].Type)
      {
         case FCV: kc *= Ucf[FLOW]; break;
         case PRV:
         case PSV:
         case PBV: kc *= Ucf[PRESSURE]; break;
      }
      km = Link[n].Km*SQR(d)*SQR(d)/0.02517;

      sprintf(s," %-31s %-31s %-31s %12.4f %5s",
         Link[n].ID,
         Node[Link[n].N1].ID,
         Node[Link[n].N2].ID,
         d*Ucf[DIAM],
         LinkTxt[Link[n].Type]);

      if (Link[n].Type == GPV && (j = ROUND(Link[n].Kc)) > 0)
         sprintf(s1,"%-31s %12.4f", Curve[j].ID, km);
      else sprintf(s1,"%12.4f %12.4f",kc,km);

      fprintf(f, "\n%s %s", s,s1);
   }

/* Write [DEMANDS] section */
   
   fprintf(f, "\n\n[DEMANDS]");
   ucf = Ucf[DEMAND];
   for (i=1; i<=Njuncs; i++)
   {
      for (demand = Node[i].D; demand != NULL; demand = demand->next)
      {
         sprintf(s," %-31s %14.6f",Node[i].ID,ucf*demand->Base);
         if ((j = demand->Pat) > 0) sprintf(s1,"   %s",Pattern[j].ID);
         else strcpy(s1,"");
         fprintf(f,"\n%s %s",s,s1);
      }
   }

/* Write [EMITTERS] section */

   fprintf(f, "\n\n[EMITTERS]");
   for (i=1; i<=Njuncs; i++)
   {
      if (Node[i].Ke == 0.0) continue;
      ke = Ucf[FLOW]/pow(Ucf[PRESSURE]*Node[i].Ke,(1.0/Qexp));
      fprintf(f,"\n %-31s %14.6f",Node[i].ID,ke);
   }

/* Write [STATUS] section */

   fprintf(f, "\n\n[STATUS]");
   for (i=1; i<=Nlinks; i++)
   {
      if (Link[i].Type <= PUMP)
      {
         if (Link[i].Stat == CLOSED)
            fprintf(f, "\n %-31s %s",Link[i].ID,StatTxt[CLOSED]);

      /* Write pump speed here for pumps with old-style pump curve input */
         else if (Link[i].Type == PUMP)
         {
            n = PUMPINDEX(i);
            if (
                 Pump[n].Hcurve == 0 &&
                 Pump[n].Ptype != CONST_HP &&
                 Link[i].Kc != 1.0
               )
               fprintf(f, "\n %-31s %-.4f",Link[i].ID, Link[i].Kc);
         }
      }

   /* Write fixed-status PRVs & PSVs (setting = MISSING) */
      else if (Link[i].Kc == MISSING)
      {
         if (Link[i].Stat == OPEN)
            fprintf(f, "\n %-31s %s",Link[i].ID,StatTxt[OPEN]);
         if (Link[i].Stat == CLOSED)
            fprintf(f, "\n%-31s %s",Link[i].ID,StatTxt[CLOSED]);
      }
   }

/* Write [PATTERNS] section */
/* (Use 6 pattern factors per line) */

   fprintf(f, "\n\n[PATTERNS]");
   for (i=1; i<=Npats; i++)
   {
      for (j=0; j<Pattern[i].Length; j++)
      {
        if (j % 6 == 0) fprintf(f,"\n %-31s",Pattern[i].ID);
        fprintf(f," %12.4f",Pattern[i].F[j]);
      }
   }

/* Write [CURVES] section */

   fprintf(f, "\n\n[CURVES]");
   for (i=1; i<=Ncurves; i++)
   {
      for (j=0; j<Curve[i].Npts; j++)
         fprintf(f,"\n %-31s %12.4f %12.4f",
            Curve[i].ID,Curve[i].X[j],Curve[i].Y[j]);
   }

/* Write [CONTROLS] section */

   fprintf(f, "\n\n[CONTROLS]");
   for (i=1; i<=Ncontrols; i++)
   {
   /* Check that controlled link exists */
      if ( (j = Control[i].Link) <= 0) continue;

   /* Get text of control's link status/setting */
      if (Control[i].Setting == MISSING)
         sprintf(s, " LINK %s %s ", Link[j].ID, StatTxt[Control[i].Status]);
      else
      {
         kc = Control[i].Setting;
         switch(Link[j].Type)
         {
            case PRV:
            case PSV:
            case PBV: kc *= Ucf[PRESSURE]; break;
            case FCV: kc *= Ucf[FLOW];     break;
         }
         sprintf(s, " LINK %s %.4f",Link[j].ID, kc);
      }
      
      switch (Control[i].Type)
      {
      /* Print level control */
         case LOWLEVEL:
         case HILEVEL:
            n = Control[i].Node;
            kc = Control[i].Grade - Node[n].El;
            if (n > Njuncs) kc *= Ucf[HEAD];
            else            kc *= Ucf[PRESSURE];
            fprintf(f, "\n%s IF NODE %s %s %.4f", s,
               Node[n].ID, ControlTxt[Control[i].Type], kc);
            break;

      /* Print timer control */
         case TIMER:
            fprintf(f, "\n%s AT %s %.4f HOURS",
               s, ControlTxt[TIMER], Control[i].Time/3600.);
            break;
                         
      /* Print time-of-day control */
         case TIMEOFDAY:
            fprintf(f, "\n%s AT %s %s",
               s, ControlTxt[TIMEOFDAY], clocktime(Atime, Control[i].Time));
            break;
      }
   }            

/* Write [QUALITY] section */
/* (Skip nodes with default quality of 0) */

   fprintf(f, "\n\n[QUALITY]");
   for (i=1; i<=Nnodes; i++)
   {
      if (Node[i].C0 == 0.0) continue;
      fprintf(f, "\n %-31s %14.6f",Node[i].ID,Node[i].C0*Ucf[QUALITY]);
   }
      
/* Write [SOURCES] section */

   fprintf(f, "\n\n[SOURCES]");
   for (i=1; i<=Nnodes; i++)
   {
      source = Node[i].S;
      if (source == NULL) continue;
      sprintf(s," %-31s %-8s %14.6f",
         Node[i].ID,
         SourceTxt[source->Type],
         source->C0);
      if ((j = source->Pat) > 0)
         sprintf(s1,"%s",Pattern[j].ID);
      else strcpy(s1,"");
      fprintf(f,"\n%s %s",s,s1);
   }

/* Write [MIXING] section */

   fprintf(f, "\n\n[MIXING]");
   for (i=1; i<=Ntanks; i++)
   {
      if (Tank[i].A == 0.0) continue;
      fprintf(f, "\n %-31s %-8s %12.4f",
              Node[Tank[i].Node].ID,
              MixTxt[Tank[i].MixModel],
              (Tank[i].V1max/Tank[i].Vmax));
   }

/* Write [REACTIONS] section */

   fprintf(f, "\n\n[REACTIONS]");
   fprintf(f, "\n ORDER  BULK            %-.2f", BulkOrder);
   fprintf(f, "\n ORDER  WALL            %-.0f", WallOrder);
   fprintf(f, "\n ORDER  TANK            %-.2f", TankOrder);
   fprintf(f, "\n GLOBAL BULK            %-.6f", Kbulk*SECperDAY);
   fprintf(f, "\n GLOBAL WALL            %-.6f", Kwall*SECperDAY);
   if (Climit > 0.0) 
   fprintf(f, "\n LIMITING POTENTIAL     %-.6f", Climit);
   if (Rfactor != MISSING && Rfactor != 0.0)
   fprintf(f, "\n ROUGHNESS CORRELATION  %-.6f",Rfactor);
   for (i=1; i<=Nlinks; i++)
   {
      if (Link[i].Type > PIPE) continue;
      if (Link[i].Kb != Kbulk)
         fprintf(f, "\n BULK   %-31s %-.6f",Link[i].ID,Link[i].Kb*SECperDAY);
      if (Link[i].Kw != Kwall)
         fprintf(f, "\n WALL   %-31s %-.6f",Link[i].ID,Link[i].Kw*SECperDAY);
   }
   for (i=1; i<=Ntanks; i++)
   {
      if (Tank[i].A == 0.0) continue;
      if (Tank[i].Kb != Kbulk)
         fprintf(f, "\n TANK   %-31s %-.6f",Node[Tank[i].Node].ID,
            Tank[i].Kb*SECperDAY);
   }

/* Write [ENERGY] section */

   fprintf(f, "\n\n[ENERGY]");
   if (Ecost != 0.0)
   fprintf(f, "\n GLOBAL PRICE        %-.4f", Ecost);
   if (Epat != 0)
   fprintf(f, "\n GLOBAL PATTERN      %s",  Pattern[Epat].ID);
   fprintf(f, "\n GLOBAL EFFIC        %-.4f", Epump);
   fprintf(f, "\n DEMAND CHARGE       %-.4f", Dcost);
   for (i=1; i<=Npumps; i++)
   {
      if (Pump[i].Ecost > 0.0)
         fprintf(f, "\n PUMP %-31s PRICE   %-.4f",
            Link[Pump[i].Link].ID,Pump[i].Ecost);
      if (Pump[i].Epat > 0.0)
         fprintf(f, "\n PUMP %-31s PATTERN %s",
            Link[Pump[i].Link].ID,Pattern[Pump[i].Epat].ID);
      if (Pump[i].Ecurve > 0.0)
         fprintf(f, "\n PUMP %-31s EFFIC   %s",
            Link[Pump[i].Link].ID,Curve[Pump[i].Ecurve].ID); 
   }

/* Write [TIMES] section */

   fprintf(f, "\n\n[TIMES]");
   fprintf(f, "\n DURATION            %s",clocktime(Atime,Dur));
   fprintf(f, "\n HYDRAULIC TIMESTEP  %s",clocktime(Atime,Hstep));
   fprintf(f, "\n QUALITY TIMESTEP    %s",clocktime(Atime,Qstep));
   fprintf(f, "\n REPORT TIMESTEP     %s",clocktime(Atime,Rstep));
   fprintf(f, "\n REPORT START        %s",clocktime(Atime,Rstart));
   fprintf(f, "\n PATTERN TIMESTEP    %s",clocktime(Atime,Pstep));
   fprintf(f, "\n PATTERN START       %s",clocktime(Atime,Pstart));
   fprintf(f, "\n RULE TIMESTEP       %s",clocktime(Atime,Rulestep));
   fprintf(f, "\n START CLOCKTIME     %s",clocktime(Atime,Tstart));
   fprintf(f, "\n STATISTIC           %s",TstatTxt[Tstatflag]);

/* Write [OPTIONS] section */

   fprintf(f, "\n\n[OPTIONS]");
   fprintf(f, "\n UNITS               %s", FlowUnitsTxt[Flowflag]);
   fprintf(f, "\n PRESSURE            %s", PressUnitsTxt[Pressflag]);                          
   fprintf(f, "\n HEADLOSS            %s", FormTxt[Formflag]);
   if (DefPat >= 1 && DefPat <= Npats)
   fprintf(f, "\n PATTERN             %s", Pattern[DefPat].ID);
   if (Hydflag == USE)                        
   fprintf(f, "\n HYDRAULICS USE      %s", HydFname);
   if (Hydflag == SAVE)
   fprintf(f, "\n HYDRAULICS SAVE     %s", HydFname);
   if (ExtraIter == -1)
   fprintf(f, "\n UNBALANCED          STOP");
   if (ExtraIter >= 0)
   fprintf(f, "\n UNBALANCED          CONTINUE %d", ExtraIter); 
   if (Qualflag == CHEM)
   fprintf(f, "\n QUALITY             %s %s", ChemName, ChemUnits);
   if (Qualflag == TRACE)
   fprintf(f, "\n QUALITY             TRACE %-31s", Node[TraceNode].ID);
   if (Qualflag == AGE)
   fprintf(f, "\n QUALITY             AGE");
   if (Qualflag == NONE)
   fprintf(f, "\n QUALITY             NONE");
   fprintf(f, "\n DEMAND MULTIPLIER   %-.4f", Dmult);
   fprintf(f, "\n EMITTER EXPONENT    %-.4f", 1.0/Qexp);
   fprintf(f, "\n VISCOSITY           %-.6f", Viscos/VISCOS);                                  
   fprintf(f, "\n DIFFUSIVITY         %-.6f", Diffus/DIFFUS);                                  
   fprintf(f, "\n SPECIFIC GRAVITY    %-.6f", SpGrav);                                  
   fprintf(f, "\n TRIALS              %-d",   MaxIter);                                  
   fprintf(f, "\n ACCURACY            %-.8f", Hacc);                                  
   fprintf(f, "\n TOLERANCE           %-.8f", Ctol*Ucf[QUALITY]);
   fprintf(f, "\n CHECKFREQ           %-d", CheckFreq);
   fprintf(f, "\n MAXCHECK            %-d", MaxCheck);
   fprintf(f, "\n DAMPLIMIT           %-.8f", DampLimit);

/* Write [REPORT] section */

   fprintf(f, "\n\n[REPORT]");
   fprintf(f, "\n PAGESIZE            %d", PageSize);
   fprintf(f, "\n STATUS              %s", RptFlagTxt[Statflag]);
   fprintf(f, "\n SUMMARY             %s", RptFlagTxt[Summaryflag]);
   fprintf(f, "\n ENERGY              %s", RptFlagTxt[Energyflag]);
   fprintf(f, "\n MESSAGES            %s", RptFlagTxt[Messageflag]);
   if (strlen(Rpt2Fname) > 0)
   fprintf(f, "\n FILE                %s", Rpt2Fname);
   switch (Nodeflag)
   {
      case 0:
      fprintf(f, "\n NODES               NONE");
      break;
      case 1:
      fprintf(f, "\n NODES               ALL");
      break;
      default:
      j = 0;
      for (i=1; i<=Nnodes; i++)
      {
         if (Node[i].Rpt == 1)
         {
            if (j % 5 == 0) fprintf(f, "\n NODES               ");
            fprintf(f, "%s ", Node[i].ID);
            j++;
         }
      }
   }
   switch (Linkflag)
   {
      case 0:
      fprintf(f, "\n LINKS               NONE");
      break;
      case 1:
      fprintf(f, "\n LINKS               ALL");
      break;
      default:
      j = 0;
      for (i=1; i<=Nlinks; i++)
      {
         if (Link[i].Rpt == 1)
         {
            if (j % 5 == 0) fprintf(f, "\n LINKS               ");
            fprintf(f, "%s ", Link[i].ID);
            j++;
         }
      }
   }
   for (i=0; i<FRICTION; i++)
   {
      if (Field[i].Enabled == TRUE)
      {
         fprintf(f, "\n %-20sPRECISION %d", Field[i].Name, Field[i].Precision);
         if (Field[i].RptLim[LOW] < BIG)
            fprintf(f, "\n %-20sBELOW %.6f", Field[i].Name, Field[i].RptLim[LOW]);
         if (Field[i].RptLim[HI] > -BIG)
            fprintf(f, "\n %-20sABOVE %.6f", Field[i].Name, Field[i].RptLim[HI]);
      }
      else fprintf(f, "\n %-20sNO", Field[i].Name);
   }
   fprintf(f, "\n\n");

/* Write [COORDINATES] section */

   if (Coordflag == TRUE)
   {
      fprintf(f, "\n\n[COORDINATES]");
      for (i=1; i<=Nnodes; i++)
      {
          if (Coord[i].HaveCoords == TRUE)
          {
              fprintf(f,"\n %-31s %14.6f %14.6f",Node[i].ID,Coord[i].X,Coord[i].Y);
          }
      }
      fprintf(f, "\n\n"); 
   }

/* Save auxilary data to new input file */
   
   saveauxdata(f); 

/* Close the new input file */

   fprintf(f, "\n[END]");
   fclose(f);
   return(0);
}

