## Copyright (C) 2012-2015 pdiribarne
##
## This file is part of Octave.
##
## Octave 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.
##
## Octave 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 Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {} {@var{s} =} hdl2struct (@var{h})
## Return a structure, @var{s}, whose fields describe the properties
## of the object, and its children, associated with the handle, @var{h}.
## 
## The fields of the structure @var{s} are @qcode{"type"}, @qcode{"handle"},
## @qcode{"properties"}, @qcode{"children"}, and @qcode{"special"}.
## @seealso{struct2hdl, hgsave, findobj}
## @end deftypefn

## Author: pdiribarne <pdiribarne@new-host.home>
## Created: 2012-03-04

function s = hdl2struct (h)

  if (nargin != 1 || ! ishandle (h))
    print_usage ();
  endif

  hiddenh = get (0, "showhiddenhandles");
  if (strcmp (hiddenh, "off"))
    set (0, "showhiddenhandles", "on");
  endif

  ## main object
  main = get (h);
  s.handle = h;
  s.type =  main.type;
  s.properties  = getprops (h);
  s.children = [];
  s.special = [];

  ## sweep all children
  kids = get (h, "children");
  nkids = length (kids);
  ii = 1;
  while (nkids)
    s.children(ii++) = hdl2struct (kids(nkids));
    nkids--;
  endwhile

  ## Special:
  special = [];
  ##  * Axes : title, xlabel, y, z
  if (strcmp (main.type, "axes"))
    special = [get(s.handle, "title"); 
               get(s.handle, "xlabel");
               get(s.handle, "ylabel");
               get(s.handle, "zlabel")];
    
    special = arrayfun (@(x) find (x == [s.children.handle]),
                        special);
  endif
  set (0, "showhiddenhandles", hiddenh);
endfunction

function prpstr = getprops (h)

  obj = get (h);
  allfields = fieldnames (obj);

  ## Remove readonly fields
  writablefields = fieldnames (set (h));
  isreadonly = cellfun (@(s) ! any (strcmp (writablefields, s)), ...
                        allfields);
  obj = rmfield (obj, allfields(isreadonly));
  allfields = fieldnames (obj);
  
  ## Reject handles and other problematic properties
  forbid = {"appdata", "beingdeleted", "busyaction", ...
            "children", "clipping", "hittest", ...
            "interruptible", "parent", "selected" ,...
            "selectionhighlight", "selectedobject", "__modified__", ...
            "uicontextmenu", "__graphics_toolkit__", "currentaxes", ...
            "currentcharacter", "currentobject", ...
            "currentpoint", "xlabel", "ylabel", ...
            "zlabel", "title"};
  isforbidden = cellfun (@(s) any (strcmp (forbid, s)), allfields);
  prpstr = rmfield (obj, allfields(isforbidden));

  ## hidden properties
  hidden = {"autopos_tag", "looseinset"};
  for ii = 1:numel (hidden)
    if (isprop (h, hidden{ii}))
      prpstr.(hidden{ii}) = get (h, hidden{ii});
    endif
  endfor

endfunction

## FIXME: need validation tests
