//-----------------------------------------------------------------------------
// Copyright (c) 2014 Guy Allard
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "guiBTViewCtrl.h"

#include "gfx/gfxDrawUtil.h"
#include "gui/worldEditor/editorIconRegistry.h"
#include "gui/controls/guiTextEditCtrl.h"

using namespace BadBehavior;

IMPLEMENT_CONOBJECT(GuiBehaviorTreeViewCtrl);

void GuiBehaviorTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool )
{
   if( !mVisibleItems.size() )
      return;

   // Do some sanity checking and data retrieval.
   AssertFatal(cell.y < mVisibleItems.size(), "GuiTreeViewCtrl::onRenderCell: invalid cell");
   Item * item = mVisibleItems[cell.y];

   // If there's no object, deal with it.
   if(item->isInspectorData())
      if(!item->getObject())
         return;

   RectI drawRect( offset, mCellSize );
   GFXDrawUtil *drawer = GFX->getDrawUtil();
   drawer->clearBitmapModulation();

   FrameAllocatorMarker txtBuff;
   
   // Ok, we have the item. There are a few possibilities at this point:
   //    - We need to draw inheritance lines and a treeview-chosen icon
   //       OR
   //    - We have to draw an item-dependent icon
   //    - If we're mouseover, we have to highlight it.
   //
   //    - We have to draw the text for the item
   //       - Taking into account various mouseover states
   //       - Taking into account the value (set or not)
   //       - If it's an inspector data, we have to do some custom rendering
   //       - ADDED: If it is being renamed, we also have custom rendering.

   // Ok, first draw the tab and icon.

   // Do we draw the tree lines?
   if( mFlags.test(ShowTreeLines) )
   {
      drawRect.point.x += ( mTabSize * item->mTabLevel );
      Item* parent = item->mParent;
      for ( S32 i = item->mTabLevel; ( parent && i > 0 ); i-- )
      {
         drawRect.point.x -= mTabSize;
         if ( parent->mNext )
            drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[BmpLine] );

         parent = parent->mParent;
      }
   }

   // Now, the icon...
   drawRect.point.x = offset.x + mTabSize * item->mTabLevel;

   // First, draw the rollover glow, if it's an inner node.
   if ( item->isParent() && item->mState.test( Item::MouseOverBmp ) )
      drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[BmpGlow] );

   // Now, do we draw a treeview-selected item or an item dependent one?
   S32 newOffset = 0; // This is stored so we can render glow, then update render pos.

   S32 bitmap = 0;

   // Ok, draw the treeview lines as appropriate.
   
   bool drawBitmap = true;
   if ( !item->isParent() )
   {
      if( mFlags.test( ShowTreeLines ) )
      {
         if(    ( item->mNext && item->mPrevious )
             || ( item->mNext && item->mParent && ( !_isRootLevelItem( item ) || mShowRoot ) ) )
            bitmap = BmpChild;
         else if( item->mNext && ( !item->mParent || !mShowRoot ) )
            bitmap = BmpFirstChild;
         else if( item->mPrevious || ( item->mParent && !_isRootLevelItem( item ) ) )
            bitmap = BmpLastChild;
         else
            drawBitmap = false;
      }
      else
         drawBitmap = false;
   }
   else
   {
      bitmap = item->isExpanded() ? BmpExp : BmpCon;

      if( mFlags.test( ShowTreeLines ) )
      {
         // Shift indices to show versions with tree lines.
         
         if ( item->mParent || item->mPrevious )
            bitmap += ( item->mNext ? 3 : 2 );
         else
            bitmap += ( item->mNext ? 1 : 0 );
      }
   }

   if( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) )
   {
      if( drawBitmap )
         drawer->drawBitmapSR( mProfile->mTextureObject, drawRect.point, mProfile->mBitmapArrayRects[bitmap] );
      newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x;
   }

   if(item->isInspectorData())
   {
      // draw lock icon if need be
      S32 icon = Lock1;
      S32 icon2 = Hidden;

      if (item->getObject() && item->getObject()->isLocked())
      {
         if (mIconTable[icon])
         {
            //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
            drawRect.point.x += mIconTable[icon].getWidth();
            drawer->drawBitmap( mIconTable[icon], drawRect.point );
         }
      }

      if (item->getObject() && item->getObject()->isHidden())
      {
         if (mIconTable[icon2])
         {
            //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
            drawRect.point.x += mIconTable[icon2].getWidth();
            drawer->drawBitmap( mIconTable[icon2], drawRect.point );
         }
      }

      /*SimObject * pObject = item->getObject();
      SimGroup  * pGroup  = ( pObject == NULL ) ? NULL : dynamic_cast<SimGroup*>( pObject );

      // If this item is a VirtualParent we can use the generic SimGroup123 icons.
      // However if there is already an icon in the EditorIconRegistry for this
      // exact class (not counting parent class icons) we want to use that instead.
      bool hasClassIcon = gEditorIcons.hasIconNoRecurse( pObject );

      // draw the icon associated with the item
      if ( !hasClassIcon && item->mState.test(Item::VirtualParent))
      {
         if ( pGroup != NULL)
         {
            if (item->isExpanded())
               item->mIcon = SimGroup1;
            else
               item->mIcon = SimGroup2;
         }
         else
            item->mIcon = SimGroup2;
      }
      
      if ( !hasClassIcon && item->mState.test(Item::Marked))
      {
         if (item->isInspectorData())
         {
            if ( pGroup != NULL )
            {
               if (item->isExpanded())
                  item->mIcon = SimGroup3;
               else
                  item->mIcon = SimGroup4;
            }
         }
      }*/

      GFXTexHandle iconHandle;

      if ( ( item->mIcon != -1 ) && mIconTable[item->mIcon] )
         iconHandle = mIconTable[item->mIcon];
#ifdef TORQUE_TOOLS
      else
         iconHandle = gEditorIcons.findIcon( item->getObject() );
#endif

      if ( iconHandle.isValid() )
      {
         S32 iconHeight = (mItemHeight - iconHandle.getHeight()) / 2;
         S32 oldHeight = drawRect.point.y;
         if(iconHeight > 0)
            drawRect.point.y += iconHeight;
         drawRect.point.x += iconHandle.getWidth();
         drawer->drawBitmap( iconHandle, drawRect.point );
         drawRect.point.y = oldHeight;
      }
   }
   else
   {
      S32 icon = item->isExpanded() ? item->mScriptInfo.mExpandedImage : item->mScriptInfo.mNormalImage;
      if ( icon )
      {
         if (mIconTable[icon])
         {
            S32 iconHeight = (mItemHeight - mIconTable[icon].getHeight()) / 2;
            S32 oldHeight = drawRect.point.y;
            if(iconHeight > 0)
               drawRect.point.y += iconHeight;
            drawRect.point.x += mIconTable[icon].getWidth();
            drawer->drawBitmap( mIconTable[icon], drawRect.point );
            drawRect.point.y = oldHeight;
         }
      }
   }

   // Ok, update offset so we can render some text!
   drawRect.point.x += newOffset;

   // Ok, now we're off to rendering the actual data for the treeview item.

   U32 bufLen = 1024; //item->mDataRenderWidth + 1;
   char *displayText = (char *)txtBuff.alloc(bufLen);
   displayText[bufLen-1] = 0;
   item->getDisplayText(bufLen, displayText);

   // Draw the rollover/selected bitmap, if one was specified.
   drawRect.extent.x = mProfile->mFont->getStrWidth( displayText ) + ( 2 * mTextOffset );
   if ( item->mState.test( Item::Selected ) && mTexSelected )
      drawer->drawBitmapStretch( mTexSelected, drawRect );
   else if ( item->mState.test( Item::MouseOverText ) && mTexRollover )
      drawer->drawBitmapStretch( mTexRollover, drawRect );

   // Offset a bit so as to space text properly.
   drawRect.point.x += mTextOffset;

   // Determine what color the font should be.
   ColorI fontColor;

   fontColor = item->mState.test( Item::Selected ) ? mProfile->mFontColorSEL :
             ( item->mState.test( Item::MouseOverText ) ? mProfile->mFontColorHL : mProfile->mFontColor );

   if (item->mState.test(Item::Selected))
   {
      drawer->drawRectFill(drawRect, mProfile->mFillColorSEL);
   }
   else if (item->mState.test(Item::MouseOverText))
   {
      drawer->drawRectFill(drawRect, mProfile->mFillColorHL);
   }

   if( item->mState.test(Item::MouseOverText) )
   {
		fontColor	=	mProfile->mFontColorHL;
   }

   drawer->setBitmapModulation( fontColor );

   // Center the text horizontally.
   S32 height = (mItemHeight - mProfile->mFont->getHeight()) / 2;

   if(height > 0)
      drawRect.point.y += height;

   // JDD - offset by two pixels or so to keep the text from rendering RIGHT ONTOP of the outline
   drawRect.point.x += 2;

   drawer->drawText( mProfile->mFont, drawRect.point, displayText, mProfile->mFontColors );

   if ( mRenamingItem == item && mRenameCtrl )
   {
      Point2I ctrPos = globalToLocalCoord( drawRect.point );
      ctrPos.y -= height;
      ctrPos.x -= 2;

      Point2I ctrExtent( getWidth() - ctrPos.x, drawRect.extent.y );

      mRenameCtrl->setPosition( ctrPos );
      mRenameCtrl->setExtent( ctrExtent );
      mRenameCtrl->setVisible( true );
   }
}