(* :Title: CheckDB *)

(* :Author: Frederik Orellana *)

(* ------------------------------------------------------------------------ *)
(* :History: created 4 October 2003 at 21:52 *)
(* ------------------------------------------------------------------------ *)

(* ------------------------------------------------------------------------ *)

BeginPackage["HighEnergyPhysics`fctables`CheckDB`",
             "HighEnergyPhysics`FeynCalc`"];

CheckDB::"usage" = 
"CheckDB[exp, fil] saves (with Put) or retrieves (with Get) exp to/from a file fil.
It checks if the setting of the option Directory \
is a valid directory name and if fil is a valid file name and does exist. \
If it does, Get[fil] is executed. \
If fil does not exist, exp gets evaluated and saved to fil. \
Saving and evaluating can be further controlled with the options ForceSave and NoSave. \
If the option Check is set to False the return value is what is evaluated (see above). \
If Check is set to True the return value is True or False depending on \
whether the evaluation of exp agrees with what is loaded from fil or fil does not \
exist. \
Default value of Check : False. \
NOTICE : If fil ends with \".Gen\" or \".Mod\", \
the setting of Directory is ignored and fil is saved in the \"CouplingVectors\" \
subdirectory of \"Phi\". If fil ends with \".Fac\", \
the setting of Directory is ignored and fil is saved in the \"Factors\" \
subdirectory of \"Phi\". If fil is a file name with full path, the setting of Directory \
is also ignored.";

ForceSave::"usage" = 
    "ForceSave is an option of CheckDB. Setting it to True forces the first argument to \
be evaluated even if the file specified by the second argument exists.  \
The expression is also saved if NoSave is set to False.  Default value : False.";

NoSave::"usage" = 
    "NoSave is an option of CheckDB. If set to True, no results will ever be saved to disk. \
It is there to allow evaluating notebooks using CheckDB without having to worry about \
overwriting old results (SetOptions[CheckDB,NoSave->True]).  Default value : False.";

CheckDB::"nostring" = 
    "`1` is not a string.  Please give the file name as a string.";
    
CheckDB::"baddir" = 
    "`1` is not a valid directory.  Please set the option Directory \
correctly.";

(* ------------------------------------------------------------------------ *)

Begin["`Private`"];

(* ------------------------------------------------------------------------ *)

Options[CheckDB] = {Directory :> ToFileName[{$FeynCalcDirectory}, "fcdb"],
    ForceSave -> False, NoSave -> False, Check -> False};

(* ------------------------------------------------------------------------ *)

VerbosePrint[n_Integer,s__]:=If[$VeryVerbose>=n,Print[s]];

eliminateDoubles[s_String] :=
    Block[{str},
      str = FixedPoint[
          StringReplace[#,
              Evaluate[$PathnameSeparator <> $PathnameSeparator] ->
                Evaluate[$PathnameSeparator]] &, s];
      If[StringMatchQ[str, "*" <> $PathnameSeparator], StringDrop[str, -1],
        str]];


SetAttributes[CheckDB, HoldFirst];

CheckDB[ex_, fi_, opts : ((_Rule | {___Rule}) ...)] :=
    Block[{ch, dir, file, finex, fs, ns, checkok=True},

      If[StringQ[fi] =!= True, Message[CheckDB::nostring, fi];
        Return[ex]];

      Which[
         StringMatchQ[fi,"*.Gen"]===True||StringMatchQ[fi,"*.Mod"]===True,
           dir = eliminateDoubles[HighEnergyPhysics`FeynCalc`$FeynCalcDirectory <>
	       $PathnameSeparator <>
	       "Phi" <> $PathnameSeparator <> "CouplingVectors"],
          StringMatchQ[fi,"*.Fac"]===True || StringMatchQ[fi,"*.Mass"]===True,
           dir = eliminateDoubles[HighEnergyPhysics`FeynCalc`$FeynCalcDirectory <>
	       $PathnameSeparator <>
	       "Phi" <> $PathnameSeparator <> "Factors"],
	      True,
           dir = (Directory /. Flatten[{opts}] /. Options[CheckDB])
      ];

      Which[

        (*File name given with full path*)
        DirectoryName[fi] =!= "",
        If[FileType[DirectoryName[fi]] === Directory, file = fi],

        (*Directory specified ok*)
        FileType[dir] === Directory,
        file = eliminateDoubles[dir <> $PathnameSeparator <> fi],

        (*Directory specified not ok, try Directory[]*)

        FileType[eliminateDoubles[Directory[] <> $PathnameSeparator <> dir]] ===
           Directory,
        file = eliminateDoubles[
              Directory[] <> $PathnameSeparator <> dir <> $PathnameSeparator <>
                 fi,

        True, (Message[CheckDB::baddir, dir]; Return[ex])];

        ];

      VerbosePrint[1, "Using file name " <> file];

      fs=(ForceSave/.Flatten[{opts}]/.Options[CheckDB]);
      ns=(NoSave/.Flatten[{opts}]/.Options[CheckDB]);
      ch=(Check/.Flatten[{opts}]/.Options[CheckDB]);

      If[(FileType[file] === None || fs === True) && ch === False,
      
        If[FileType[file] === None,
          VerbosePrint[1, "File does not exist, evaluating"],
          If[fs,VerbosePrint[1, "File exists, force evaluating"]]
        ];
        finex = Evaluate[ReleaseHold[ex]];
        If[ns,
          VerbosePrint[1, "NoSave set to True, will evaluate but not save"],
          VerbosePrint[1, "Saving"];
          Put[finex, file]
        ],
        
        If[FileType[file] === None && fs =!= True,
          VerbosePrint[1, "File does not exist, cannot load"];
          finex = ex,
          VerbosePrint[1, "File exists, loading"];
          finex = Get[file];
          If[ch,
            VerbosePrint[1, "File exists, comparing"];
            finex = (Expand[Evaluate[ReleaseHold[ex]] - finex] === 0)
          ]
        ];
        
      ];

      finex

      ];

End[]; EndPackage[];

(* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *)
If[$VeryVerbose > 0,WriteString["stdout", "CheckDB | \n "]];
Null
(* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *)
