## Copyright (C) 2014 Eugenio Gianniti <eugenio.gianniti@mail.polimi.it>
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 3 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, see <http://www.gnu.org/licenses/>.


## -*- texinfo -*-
## @deftypefn {Function File} ufl [command] line
##
## Writes the given line to a ufl file. Optional commands are:
## @itemize @bullet
## @item start: opens an ufl file. It is possible to specify a name for it,
## otherwise "default.ufl" will be used.
## @item end: closes the ufl file and compiles it. It is possible to 
## specify its @var{content}, otherwise a complete problem is assumed.
## Possible options are: BilinearForm, Functional, FunctionSpace, LinearForm
## and Problem.
## @end itemize
##
## @example
## @code{ufl start linform}
## @code{ufl element = FiniteElement ("Lagrange", triangle, 1)}
## @code{ufl v = TestFunction (element)}
## @code{ufl f = Coefficient (element)}
## @code{ufl L = f*v*dx}
## @code{ufl end LinearForm}
## @end example
##
## This way you can write a ufl file and compile it obtaining a LinearForm.
##
## Be aware that a ufl line starting with brackets will result in a syntax
## error. To avoid this, it is necessary to enclose them and their content
## in quotes or apices:
## @example
## @code{ufl "(sigma, u)" = TrialFunctions(W)}
## @end example
##
## @seealso{import_ufl_Problem, import_ufl_BilinearForm, import_ufl_Functional,
## import_ufl_FunctionSpace, import_ufl_LinearForm} 
## @end deftypefn

function ufl (varargin)

  persistent fid = -1;
  persistent filename = "default.ufl";
  persistent opts = {"BilinearForm",
                     "Functional",
                     "FunctionSpace",
                     "LinearForm",
                     "Problem"};

  if (numel (varargin) < 1)
    if (is_master_node () && ! is_valid_file_id (fid))
      print_usage ();
    endif
  elseif (! all (cellfun ("ischar", varargin)))
    if (is_master_node ())
      error ("ufl: all arguments should be strings");
    endif
  elseif (strcmpi (varargin{1}, "start"))
    if (is_master_node ())
      if (is_valid_file_id (fid))
        error ("ufl: a file is already open");
      else
        if (numel (varargin) > 1)
          filename = varargin{2};
          if (isempty (regexpi (filename, ".ufl$", "match")))
            filename = [filename, ".ufl"];
          else
            filename = [filename(1:end-4), ".ufl"];
          endif
        endif
        [~, err, ~] = stat (filename);
        if (err == 0)
          error (["ufl: a file named ", filename, " already exists"]);
        else
          fid = fopen (filename, "w");
        endif
      endif
      if (! is_valid_file_id (fid))
        error (["ufl: could not open file ", filename]);
      endif
    endif
  elseif (strcmpi (varargin{1}, "end"))
    if (is_master_node ())
      if (! is_valid_file_id (fid))
        error ("ufl: no open file");
      else
        fclose (fid);
        fid = -1;
      endif
    endif
    compile = "Problem";
    if (numel (varargin) > 1)
      compile = validatestring (varargin{2}, opts, "ufl", "content");
    endif
    # This line is executed by all the nodes since it internally enforces
    # that just one is involved
    eval (["import_ufl_", compile, "(\"", filename(1:end-4), "\");"]);
    if (is_master_node ())
      delete (filename);
    endif
    filename = "default.ufl";
  elseif (! is_valid_file_id (fid))
    if (is_master_node ())
      error ("ufl: no open file");
    endif
  else
    if (is_master_node ())
      if (is_valid_file_id (fid))
        output = strtrim (sprintf ("%s ", varargin{:}));
        fputs (fid, output);
        fprintf (fid, "\n");
      else
        error ("ufl: no open file");
      endif
    endif
  endif

endfunction
