/*  
 *    SCCS ID: %Z%%M% %I% %E% SST
 *
 *    Copyright (c) 1992-1993 Mark Soloway.  All rights reserved.
 *    See SST_LEGAL_NOTICE file for terms of the license. 
 */  
  
#include <sys/stat.h>
#include <string.h>

#include "CSDrawIcon.h"
#include "Image.h"
#include "ObjectTree.h"
#include "TreeDisplayer.h"
#include "TreeNode.h"
#include "TreeNode_consts.h"
#include "TreeNodeAddChildMessage.h"
#include "TreeNodeDeleteNodeMessage.h"
#include "TTGenericHash.h"
#include "TTMessage.h"
#include "TTSession.h"

#define OPENWIN_IMAGES_DIR "/include/images/"

int            TreeNode::numTreeNodes = 0;
TTGenericHash *TreeNode::treeNodeIcons = (TTGenericHash *)NULL;

TreeNode::~TreeNode ()
{
  numTreeNodes--;

  if (numTreeNodes == 0) {
    delete treeNodeIcons;
    treeNodeIcons = (TTGenericHash *)NULL;
  }
}  

Tt_status TreeNode::addChild (TreeNode &child)
{
  Tt_status               status;
  TreeNodeAddChildMessage message (*this, status);
  if (status < TT_WRN_LAST) {
    if (status < TT_WRN_LAST) {
      status = message.setChildNode (child);
    }
    
    if (status < TT_WRN_LAST) {
      status = sendMessage (message);
    }
  }

  return status;
}

Tt_status TreeNode::deleteNode ()
{
  Tt_status status;

  TreeNodeDeleteNodeMessage message (*this, status);
  if (status < TT_WRN_LAST) {
    status = sendMessage (message);
  }

  return status;
}

TreeNodeArray *TreeNode::getChildren (Tt_status &status) const
{
  TreeNodeArray *array = (TreeNodeArray *)NULL;

  if (status > TT_WRN_LAST) {
    return array;
  }

  int   num_children = getPropertyCount (TREE_NODE_CHILDREN_PROPERTY, status);
  char *objid;

  // Due to a bug in ToolTalk 1.0, map a TT_ERR_INTERNAL to a
  // TT_ERR_PROPNAME when getting a property count.
  if (status == TT_ERR_INTERNAL) status = TT_ERR_PROPNAME;

  if ((status < TT_WRN_LAST) && num_children) {
    for (int i=0; (status < TT_WRN_LAST) && (i < num_children); i++) {
      status = getProperty (TREE_NODE_CHILDREN_PROPERTY, i, objid);

      if (objid && (status < TT_WRN_LAST)) {
        TreeNode *child_node = new TreeNode (objid, status);

        if (status < TT_WRN_LAST) {
  	  if (!array) array = new TreeNodeArray;
          array->addItem (child_node); 
        }
      }
    }
  }

  if (status == TT_ERR_PROPNAME) status = TT_OK;

  return array;
}

CSDrawIcon *TreeNode::getIcon (Tt_status &status) const
{
  CSDrawIcon *icon = (CSDrawIcon *)NULL;

  TreeNodeIcon *tree_node_icon = getTreeNodeIcon (getObjectKey (status));
  if (tree_node_icon && (status < TT_WRN_LAST)) {
    icon = tree_node_icon->icon;
  }

  return icon;
}

Tt_status TreeNode::setImageFile (const char *file)
{
  Tt_status status = setImageFileProperty (file);

  if (status < TT_WRN_LAST) {
    status = manageIcon ();
  }

  return status;
}
 
char *TreeNode::getImageFile (Tt_status &status) const
{
  char *file;

  status = getProperty (TREE_NODE_IMAGE_FILE_PROPERTY, 0, file);
  return file;
}

Tt_status TreeNode::setText (const char *text)
{
  Tt_status status = setTextProperty (text);

  if (status < TT_WRN_LAST) {
    status = manageIcon ();
  }

  return status;
}

char *TreeNode::getText (Tt_status &status) const
{
  char *text;

  status = getProperty (TREE_NODE_TEXT_PROPERTY, 0, text);
  return text;
}

Tt_status TreeNode::sendMessage (TTMessage &message)
{
  Tt_status  status;
  char      *file = getFile (status);

  if (status < TT_WRN_LAST) {
    status = message.setFile (file);
  }

  if (status == TT_OK) {
    TTSession session (status);

    // Send a request synchronously for robustness.  If the status
    // is TT_OK, then we know it was successful and handled.
    status = session.sendSynchronousMessage (message);
  }

  return status;
}

Tt_status TreeNode::manageIcon (char *image_file, char *text)
{
  char      *local_image_file;
  char      *local_text;
  Tt_status  status;

  if (image_file) {
    char *slash_pos = strrchr (image_file, '/');
    if (slash_pos) {
      local_image_file = slash_pos+1;
    }
    else {
      local_image_file = image_file;
    }

    status = setImageFileProperty (local_image_file);
  }
  else {
    local_image_file = getImageFile (status);
  }

  if (status > TT_WRN_LAST) {
    return status;
  }

  if (text) {
    local_text = text;
    status = setTextProperty (local_text);
  }
  else {
    local_text = getText (status);
  }

  if (status > TT_WRN_LAST) {
    return status;
  }

  char         *object_key;
  TreeNodeIcon *icon = getTreeNodeIcon (object_key = getObjectKey (status));
  if (status > TT_WRN_LAST) {
    return status;
  }

  if (!icon) {
    icon = new TreeNodeIcon;
    setTreeNodeIcon (object_key, icon);

    icon->icon = new CSDrawIcon;
    icon->icon->setSelectable (TRUE);
    icon->icon->setExclusiveSelect (TRUE);
    icon->icon->setSelectionHandler (&TreeNode::nodeSelectionHandler);

    char *temp_objid = getID (status);
    char *object_id = strcpy (new char [strlen (temp_objid) + 1], temp_objid);
    icon->icon->setObjectData (TREE_NODE_OBJECT_ID, (Generic *)object_id);
  }

  if (local_image_file) {
    char *openwin_home = getenv ("OPENWINHOME");
    char *openwin_image_file = new char [strlen (openwin_home) +
				         strlen (OPENWIN_IMAGES_DIR) +
				         strlen (local_image_file) + 1];
    sprintf (openwin_image_file,
	     "%s%s%s",
	     openwin_home, OPENWIN_IMAGES_DIR, local_image_file);

    struct stat stat_buf;
    if (!openwin_image_file || stat(openwin_image_file, &stat_buf)) {
      if (openwin_image_file) delete openwin_image_file;
      openwin_image_file = new char [strlen (openwin_home) +
                                     strlen (OPENWIN_IMAGES_DIR) +
                                     strlen (TREE_NODE_DEFAULT_IMAGE_FILE) + 1];
      sprintf (openwin_image_file,
               "%s%s%s",
               openwin_home, OPENWIN_IMAGES_DIR, TREE_NODE_DEFAULT_IMAGE_FILE);
    }

    Image *new_image = new Image (openwin_image_file);
    icon->icon->setSelectedImage (*new_image);
    icon->icon->setSelectedImageMask (*new_image);
    icon->icon->setNotSelectedImage (*new_image);

    if (openwin_image_file) delete openwin_image_file;

    if (icon->image) {
      delete icon->image;
    }
    icon->image = new_image;
  }

  if (local_text) {
    icon->icon->setValue (local_text);
  }

  return status;
}

void TreeNode::nodeSelectionHandler (UIObject *object)
{
  CSComponent *tree_node = (CSComponent *)object;
  ObjectTree *parent = (ObjectTree *)object->getParent ();

  if (tree_node->isSelected ()) {
    char *object_id = (char *)object->getObjectData (TREE_NODE_OBJECT_ID);
    parent->setSelectedNodeID (object_id);
  }
  else {
    parent->setSelectedNodeID ((char *)NULL);
  }
}
