/*
* Author: Andrew Mann
*
* Copyright (C) 2004 PlaneShift Team (info@planeshift.it,
* http://www.planeshift.it)
*
* 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 (version 2 of the License)
* 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
*/


#include <psconfig.h>
#include "pawsscrollpane.h"
#include "partview.h"


#include "paws/pawsmanager.h"
#include "paws/pawsbutton.h"
#include "paws/pawstextbox.h"
#include "paws/pawslistbox.h"
#include "paws/pawscrollbar.h"
#include "paws/pawsborder.h"


pawsScrollPane::pawsScrollPane( PawsManager* manager )
            :pawsWidget( manager )
{
    pane_scroll=NULL;
    depth=0;
    scroll_visible=false;
    scroll_vertical=true;
    scroll_side=SCROLL_ON_RIGHT;
    mouse_dragging=false;
    
}

pawsScrollPane::~pawsScrollPane()
{
    delete pane_scroll;
}

bool pawsScrollPane::Setup( iDocumentNode* node )
{
    csRef<iDocumentNode> scrollbarnode,subnode;
    scrollbarnode = node->GetNode( "scrollbar" );
    if ( scrollbarnode )
    {
        // Check for direction 
        csRef<iDocumentAttribute> directionAttribute = scrollbarnode->GetAttribute("direction");
        if ( directionAttribute )
        {
            csString value( directionAttribute->GetValue() );
            if ( value.CompareNoCase("horizontal"))  
                scroll_vertical=false;
            else
                scroll_vertical=true;
        }

        // Check for relative location 
        csRef<iDocumentAttribute> locationAttribute = scrollbarnode->GetAttribute("location");
        if ( locationAttribute )
        {
            csString value( locationAttribute->GetValue() );
            if ( value.CompareNoCase("top") || value.CompareNoCase("left") )  
                scroll_side=SCROLL_ON_LEFT;
            else
                scroll_side=SCROLL_ON_RIGHT;
        }
    }

    return true;
}


bool pawsScrollPane::PostSetup()
{
    int attach;

    pane_scroll = ( pawsScrollBar* ) windowManager->CreateWidget( "pawsScrollBar" );
    pane_scroll->SetParent( this );

    if (scroll_vertical)
    {
        if (scroll_side==SCROLL_ON_RIGHT)
        {
            attach = ATTACH_TOP | ATTACH_BOTTOM | ATTACH_RIGHT;
            pane_scroll->SetRelativeFrame( defaultFrame.Width() - GetActualWidth(15), GetActualHeight(6),
                                        GetActualWidth(15), defaultFrame.Height() - GetActualHeight(12) );
        }
        else
        {
            attach = ATTACH_TOP | ATTACH_BOTTOM | ATTACH_LEFT;
            pane_scroll->SetRelativeFrame( 0, GetActualHeight(6),
                                        GetActualWidth(15), defaultFrame.Height() - GetActualHeight(12) );
        }
        pane_scroll->SetHorizontal(false);
    }
    else
    {
        if (scroll_side==SCROLL_ON_BOTTOM)
        {
            attach = ATTACH_LEFT | ATTACH_BOTTOM | ATTACH_RIGHT;
            pane_scroll->SetRelativeFrame( GetActualWidth(6), defaultFrame.Height() - GetActualHeight(15),
                                        defaultFrame.Width() - GetActualWidth(12),  GetActualHeight(15) );
        }
        else
        {
            attach = ATTACH_LEFT | ATTACH_TOP | ATTACH_RIGHT;
            pane_scroll->SetRelativeFrame( GetActualWidth(6), 0,
                                        defaultFrame.Width() - GetActualWidth(12),  GetActualHeight(15) );
        }

        pane_scroll->SetHorizontal(true);
    }


    
    pane_scroll->SetAttachFlags( attach );
    pane_scroll->PostSetup();
    pane_scroll->SetMaxValue(100.0f);
    pane_scroll->SetTickValue(10.0f);
    pane_scroll->SetCurrentValue(0.0f);

    // Do not start off as a child.  If a scrollbar is needed it will be added on the first draw
    //AddChild(pane_scroll);

    return true;
}


void pawsScrollPane::DrawChildren()
{
    int i;
    if (border)
    {
        // Adjust clipRect
        // This is a bit of a hack.  The clipRect in a widget with a border includes the border region
        // Children should be clipped to a smaller region to avoid overwriting the border
        if (screenFrame.xmin == clipRect.xmin)
            clipRect.xmin+=3;
        if (screenFrame.xmax == clipRect.xmax)
            clipRect.xmax-=3;
        if (screenFrame.ymin == clipRect.ymin)
            clipRect.ymin+=3;
        if (screenFrame.ymax == clipRect.ymax)
            clipRect.ymax-=3;
    }

    if (mouse_dragging)
        HandleMouseDrag();

    if (scroll_vertical)
    {
        int y;

        // Readjust the position of all children
        if (border)
            y=3;
        else
            y=0;

        for (i=0;i<children.Length();i++)
        {
            int childheight;
            csRect childframe;
            if (!children[i]->IsVisible())
                continue;
            // Don't consider the scrollbar here
            if (children[i] == pane_scroll)
                continue;

            childframe=children[i]->ScreenFrame();

            // Calculate the height needed based on the border if present
            if (children[i]->GetBorder())
                childheight=children[i]->GetBorder()->GetRect().Height();
            else
                childheight=childframe.Height();

            if (y+childheight > depth && y <(screenFrame.Height()+depth))
            {
                children[i]->SetRelativeFramePos(childframe.xmin-screenFrame.xmin,y-depth);
                children[i]->Draw();
            }
            y+=childheight;
        }
        // Scrollbar is needed
        if (y > screenFrame.Height())
        {
            int scrollrange=y-screenFrame.Height();
            if (scrollrange != pane_scroll->GetMaxValue())
                pane_scroll->SetMaxValue(scrollrange);
            if (depth != pane_scroll->GetCurrentValue())
                pane_scroll->SetCurrentValue(depth);
            if (!scroll_visible)
            {
                AddChild(pane_scroll);
                if (scroll_side==SCROLL_ON_RIGHT)
                {
                    pane_scroll->SetRelativeFrame( defaultFrame.Width() - GetActualWidth(15), GetActualHeight(6),
                                                GetActualWidth(15), defaultFrame.Height() - GetActualHeight(12) );
                }
                else
                {
                    pane_scroll->SetRelativeFrame( 0, GetActualHeight(6),
                                                GetActualWidth(15), defaultFrame.Height() - GetActualHeight(12) );
                }
                scroll_visible=true;
            }
            pane_scroll->Draw();
        }
        else
        {
            depth=0;
            if (scroll_visible)
            {
                RemoveChild(pane_scroll);
                scroll_visible=false;
            }
        }
    }
    else
    {
        int x;

        // Readjust the position of all children
        if (border)
            x=3;
        else
            x=0;

        for (i=0;i<children.Length();i++)
        {
            int childwidth;
            csRect childframe;
            if (!children[i]->IsVisible())
                continue;
            // Don't consider the scrollbar here
            if (children[i] == pane_scroll)
                continue;

            childframe=children[i]->ScreenFrame();

            // Calculate the width needed based on the border if present
            if (children[i]->GetBorder())
                childwidth=children[i]->GetBorder()->GetRect().Width();
            else
                childwidth=childframe.Width();

            if (x+childwidth > depth && x <(screenFrame.Width()+depth))
            {
                children[i]->SetRelativeFramePos(x-depth,childframe.ymin-screenFrame.ymin);
                children[i]->Draw();
            }
            x+=childwidth;
        }
        // Scrollbar is needed
        if (x > screenFrame.Width())
        {
            int scrollrange=x-screenFrame.Width();
            if (scrollrange != pane_scroll->GetMaxValue())
                pane_scroll->SetMaxValue(scrollrange);
            if (depth != pane_scroll->GetCurrentValue())
                pane_scroll->SetCurrentValue(depth);
            if (!scroll_visible)
            {
                AddChild(pane_scroll);
                if (scroll_side==SCROLL_ON_BOTTOM)
                {
                    pane_scroll->SetRelativeFrame( GetActualWidth(6), defaultFrame.Height() - GetActualHeight(15),
                                                defaultFrame.Width() - GetActualWidth(12),  GetActualHeight(15) );
                }
                else
                {
                    pane_scroll->SetRelativeFrame( GetActualWidth(6), 0,
                                                defaultFrame.Width() - GetActualWidth(12),  GetActualHeight(15) );
                }
                scroll_visible=true;
            }
            pane_scroll->Draw();
        }
        else
        {
            depth=0;
            if (scroll_visible)
            {
                RemoveChild(pane_scroll);
                scroll_visible=false;
            }
        }


    }

}

bool pawsScrollPane::OnScroll( int scrollDirection, pawsScrollBar* widget )
{
    if (!widget)
        return false;
    if (widget == pane_scroll)
    {
        depth=widget->GetCurrentValue();
    }


    return true;
}

void pawsScrollPane::HandleMouseDrag()
{
    csPoint mousePos;
    int relMouseCoord;     // coordinate of mouse cursor relative to the scroll direction of this pane

    if (!scroll_visible)
    {
        mouse_dragging=false;
        return;
    }

    mousePos = windowManager->GetMouse()->GetPosition();
    if (scroll_vertical)
    {
        if (mousePos.y > screenFrame.ymax)
        {
            mouse_dragging=false;
            mousePos.y=screenFrame.ymax;
        }
        if (mousePos.y < screenFrame.ymin)
        {
            mouse_dragging=false;
            mousePos.y=screenFrame.ymin;
        }

        relMouseCoord=mousePos.y - mouse_last_position.y;

        mouse_last_position.Set(mousePos);

        depth-=relMouseCoord;
        if (depth<0)
            depth=0;
        if (pane_scroll && (depth > pane_scroll->GetMaxValue()))
            depth = pane_scroll->GetMaxValue();
    }
    else
    {
        if (mousePos.x > screenFrame.xmax)
        {
            mouse_dragging=false;
            mousePos.x=screenFrame.xmax;
        }
        if (mousePos.x < screenFrame.xmin)
        {
            mouse_dragging=false;
            mousePos.x=screenFrame.xmin;
        }

        relMouseCoord=mousePos.x - mouse_last_position.x;

        mouse_last_position.Set(mousePos);

        depth-=relMouseCoord;

        if (depth<0)
            depth=0;
        if (pane_scroll && (depth > pane_scroll->GetMaxValue()))
            depth = pane_scroll->GetMaxValue();
    }
 
}

bool pawsScrollPane::OnMouseDown( int button, int modifiers, int x, int y )
{
    // None of the children handled this, so we'll handle it as a drag
    if (button == 1 && scroll_visible)
    {
        mouse_dragging=true;
        mouse_last_position.Set(x,y);
        return true;
    }
    if (parent)
        return parent->OnMouseDown(button,modifiers,x,y);
    return false;
}

bool pawsScrollPane::OnMouseUp( int button, int modifiers, int x, int y )
{
    // None of the children handled this, so we'll handle it as a drag
    if (button == 1 && mouse_dragging)
    {
        mouse_dragging=false;
        return true;
    }
    if (parent)
        return parent->OnMouseUp(button,modifiers,x,y);
    return false;
}


void pawsScrollPane::BringToTop( pawsWidget* widget )
{
    // Do nothing.  Do not reorder children.
}

