/*
 * @(#)DataTagBase.java
 *
 * Copyright 2001-2002 by Oracle Corporation,
 * 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Oracle Corporation.
 */

package oracle.jbo.html.jsp.datatags;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import oracle.jbo.AttributeDef;
import oracle.jbo.AttributeList;
import oracle.jbo.JboException;
import oracle.jbo.Row;
import oracle.jbo.html.DataSource;

public class DataTagBase extends TagSupport
{
   public static final String ROWKEY_PARAM = "jboRowKey";
   
   protected String            sDataSource;
   protected String            sDataItem;
   protected DataSource        ds;
   protected Row               row;
   protected AttributeDef      attrDef;
   protected String            sAttrName;
   protected String            sSubAttrName;
   protected AttributeList     attrList;

   public DataTagBase()
   {
      reset();
   }

   public void setDatasource(String sDataSource)
   {
      this.sDataSource = sDataSource;
   }

   public void setDataitem(String sValue)
   {
      this.sDataItem = sValue;
   }

   // This method try to find the first ancestor tag for a specific datasource
   public final Tag findAncestorWithClassForDataSource(java.lang.Class klass)
   {
      return Utils.findAncestorWithClassForDataSource(this, sDataSource, klass);
   }
   
   protected void initializeDataSource()
   {
      // If the datasource id is defined, used it to retrieve the datasource
      if (sDataSource != null)
      {
         ds = Utils.getDataSourceFromContext(pageContext, sDataSource);
      }
      // Otherwise try to find an attributeIterateTag in the hierachy.
      else
      {
         ds = Utils.getDataSourceFromAncestor(this);
      }

      if (ds == null)
      {
         throw new JboException(Res.getString(Res.NEED_DATASOURCE));
      }
   }

   protected void initializeRow()
   {
      row = getRowFromContext(this, sDataSource, ds);
   }
   
   public static final Row getRowFromContext(Tag from, String dataSourceName, DataSource dsIn) 
   {
      // Retrieve the row from the first RowsetIterate tag or Row tag matching our datasource name
      Row retRow = Utils.getRowFromAncestor(from, dataSourceName);

      // If Row tag failed too, use the current row
      if (retRow == null && dsIn != null)
      {
         retRow = dsIn.getRowSet().getCurrentRow();
      }

      return retRow;
   }

   protected void initializeAttributeDef()
   {
      if (sDataItem == null)
      {
         AttributeIterateTag tag = (AttributeIterateTag)findAncestorWithClassForDataSource(AttributeIterateTag.class);
         
         if (tag != null)
         {
            attrDef = tag.getAttributeDef();
         }
      }
      else if (ds != null)
      {
         int nDotIndex = sDataItem.indexOf('.');
         
         if (nDotIndex == -1)
         {
            if (!"*".equals(sDataItem))
            {
               attrDef = ds.getRowSet().getViewObject().findAttributeDef(sDataItem);
            }
         }
         else
         {
            sAttrName     = sDataItem.substring(0,nDotIndex);
            sSubAttrName  = sDataItem.substring(nDotIndex + 1);
            
            attrDef = ds.getRowSet().getViewObject().findAttributeDef(sAttrName);
            if (row != null)
            {
               attrList = (AttributeList) row.getAttribute(sAttrName);
      
               if (attrList == null)
               {
                  try
                  {
                     attrList = (AttributeList)attrDef.getJavaType().newInstance();
                  }
                  catch (Exception ex)
                  {
                     String error = Res.format(Res.CANNOT_CREATE_NEW_OBJECT, attrDef.getJavaType().getName());
                     pageContext.getServletContext().log(error, ex);
                     throw new JboException(error);
                  }
               }
            }
         }
      }
   }

   public void internalInitialize()
   {
      initializeDataSource();
      initializeRow();
      initializeAttributeDef();
   }

   /**
     * Process the start tag for this instance.
     *
     * The doStartTag() method assumes that all setter methods have been
     * invoked before.
     *
     * When this method is invoked, the body has not yet been invoked.
     *
     * @returns EVAL_BODY_INCLUDE if the tag wants to process body, SKIP_BODY if it
     * does ont want to process it.
     */
   public int doStartTag()
      throws JspException
   {
      internalInitialize();
      
      return Tag.SKIP_BODY;
   }

   // Use by the constructor and the release method to reset the member variable values
   private void reset()
   {
      sDataSource = null;
      sDataItem = null;
      ds = null;
      row = null;
      attrDef = null;
      sAttrName = null;
      sSubAttrName = null;
      attrList = null;
   }
   
   /**
     * release() called after doEndTag() to reset state
     */
   public void release()
   {
      reset();
      super.release();
   }

}
