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

## str = hdl2struct(h) :
## h is a handle to a figure.
## Returns a structure with the content of the
## graphic object and its children. Structure fields are "type",
## "handle", "properties", "children" and special    

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

function [ hgS ] = hdl2struct (h, rec = 0)
  if nargin > 2 || !ishandle (h)
    print_usage();
  endif
  
  ## recursion number
  rec++;
  if rec > 10
    error("hdl2struct: to many recursions");
  endif

  ## main object
  main = get(h);
  hgS.handle = h;
  hgS.type =  main.type;
  hgS.properties  = getprops (main, h);
  hgS.children = [];
  hgS.special = [];
  
  ## sweep all children but legends and colorbars in reverse order 
  ch = main.children;
  lg = findobj (h, "-depth", 1, "tag", "legend");
  cb = findobj (h, "-depth", 1, "tag", "colorbar");
  nch = length (ch);
  ii = 0;
  while nch
    if !any (ch (nch) == lg) && !any (ch (nch) == cb)
      ii++;
      hgS.children(ii) = hdl2struct(ch(nch), rec);
    endif
    nch--;
  endwhile

  ## look for legends and colorbars among "main"'s brothers and add them
  ## to the children list
  if strcmpi (main.type, "axes")
    par = main.parent;
    lg = findobj (par, "-depth", 1, "tag", "legend");
    if !isempty (lg)
      idx = arrayfun (@(x) get(x).userdata.handle == h, lg);
      lg = lg(find(idx));
    endif
    nlg = length (lg);
    if nlg == 1
      ii++;
      hgS.children(ii) = hdl2struct(lg, rec);
    elseif nlg > 1
      error ("hdl2struct : more than one legend found")
    endif
    
    cb = findobj (par, "-depth", 1, "tag", "colorbar");
    if !isempty (cb)
      idx = arrayfun (@(x) get(x).axes == h, cb);
      cb = cb(find(idx));
    endif

    ncb = length (cb);
    if ncb == 1
      ii++;
      hgS.children(ii) = hdl2struct(cb, rec);
    elseif nlg > 1
      error ("hdl2struct : more than one colorbar found")
    endif
  endif
  ## add non "children" children objects (title, xlabel, ...)
  special = getspecial (main, h);
  nsp = length (special);
  while nsp
    ii++;
    hgS.children(ii) = hdl2struct(special(nsp), rec);
    hgS.special(nsp) = ii;
    nsp--;
  endwhile

  
endfunction


function hdlist = getspecial (obj, h)
  ## return handles to special children
  fields = fieldnames (obj);
  hdlist = [];
  
  
  ## look for non-figure, non-root, non-children, non-parent handles
  forbid = {"children", "parent", "currentaxes"};
  nflds = numel (fields);
  ii = 1;
  while nflds
    prop = fields{nflds};
    val = obj.(fields{nflds});
    if ishandle (val) && numel (val) == 1 && \
          !any (strcmpi (forbid, prop))  
      if get (val, "parent") == h
        hdlist(ii++) = val;
      endif
    endif
    nflds--;
    
  endwhile
  
endfunction

function prpstr = getprops (obj, h)
  ## get usefull properties rejecting readonly, children, handles ...
  fields = fieldnames (obj);
  hdlist = [];
  
  forbid = {"beingdeleted", "busyaction", "buttondownfcn", ...
            "children", "clipping", "createfcn", ...
            "deletefcn", "handlevisibility", "hittest", ...
            "interruptible", "parent", "selected" ,...
            "selectionhighlight", "type", "__modified__", ...
            "uicontextmenu", "__graphics_toolkit__", "currentaxes", ...
            "currentcharacter", "currentobject","tightinset", ...
            "currentpoint", "extent", "__plotyy_axes__"};
  
  nflds = length (fields);
  ii = 0;
  while nflds
    prop = fields{nflds};
    val = obj.(fields{nflds});
    ii++;
    if !any (strcmp (prop, forbid))
      prpstr.(prop) = val;
    endif
    nflds--;
  endwhile

  ## hidden properties
  hid = {"autopos_tag", "looseinset"};
  for ii = 1:numel (hid)
    prop = hid{ii};
    try
      prpstr.(prop) = get (h, prop);
    end_try_catch
    
  endfor
  
endfunction


