/***************************************************************************
 *   Copyright (C) 2004 by Tasuku Suzuki                                   *
 *   tasuku@linux-life.net                                                 *
 *                                                                         *
 *   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 2 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <klocale.h>
#include <kdebug.h>
#include <kprinter.h>

#include "kkitem.h"
#include "kkdoc.h"
#include "kkcmdname.h"
#include "kkcmdlocation.h"
#include "kkcmdsize.h"
#include "kkcmdtext.h"
#include "kkcmdtextalign.h"
#include "kkcmdtextorientation.h"
#include "kkcmdtextcolor.h"
#include "kkcmdtextfont.h"
#include "kkcmddatafield.h"
#include "kkcmdimage.h"
#include "kkcmdimageprint.h"
#include "kkcmdlocked.h"
#include "kkcmdinsert.h"
#include "kkcmdremove.h"

KKDoc::KKDoc( KActionCollection* actionCollection, QWidget *parent, const char *name )
	: KListView(parent, name)
{
	m_cmd = NULL;
	m_actionCollection = actionCollection;
	m_cmdHistory = new KCommandHistory( m_actionCollection );
	m_clipboard.setAutoDelete( true );
	addColumn( i18n("Items") );
	setFullWidth( true );
// 	setAllColumnsShowFocus( true );
// 	setRootIsDecorated( true );
	setSortColumn( -1 );
	setSelectionModeExt( FileManager );
	setDragEnabled( false );
// 	setItemsRenameable( true );
// 	setRenameable( 0, true );
	connect( this, SIGNAL( selectionChanged() ), this, SLOT( slotSelectionChanged() ) );
}

KKDoc::KKDoc( QWidget *parent, const char *name )
	: KListView(parent, name)
{
	m_cmd = NULL;
	m_actionCollection = new KActionCollection( this);
	m_cmdHistory = new KCommandHistory( m_actionCollection );
	addColumn( i18n("Items") );
	hide();
}


KKDoc::~KKDoc()
{
}

void KKDoc::setDocument( const QDomDocument &doc )
{
	clearDocument();
	KKItem* item = NULL;
	for( QDomNode n = doc.documentElement().lastChild(); !n.isNull(); n = n.previousSibling() )
	{
		item = new KKItem( n.toElement(), this );
	}
	if( !selectedItems().isEmpty() )
	{
		setSelected( selectedItems().first(), true );
	}
	else
	{
		setSelected( firstChild(), true );
	}
	emit documentChanged();
	if( m_actionCollection->actions().count() > 3  ) /* KActionCollection has at least 2 actions */
	{
		bool bl = ( !selectedItems().isEmpty() && selectedItems().first()->parent() );
		m_actionCollection->action( "raise" )->setEnabled( bl );
		m_actionCollection->action( "lower" )->setEnabled( bl );
		m_actionCollection->action( "edit_cut" )->setEnabled( bl );
		m_actionCollection->action( "edit_copy" )->setEnabled( bl );
		m_actionCollection->action( "edit_paste" )->setEnabled( m_clipboard.count() );
	}
}

void KKDoc::clearDocument()
{
	clear();
	commandHistory()->clear();
	emit documentChanged();
}

QDomDocument KKDoc::document()
{
	QDomDocument doc;
	doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
	QDomElement elem = doc.createElement( "kreetingkard" );
	elem.setAttribute( "version", "0.1.0" );
	KKItem* base = (KKItem*)firstChild();
	while( base )
	{
		elem.appendChild( base->toElement( doc ) );
		base = (KKItem*)base->nextSibling();
	}
	doc.appendChild( elem );
	return doc;
}

void KKDoc::terminate()
{
	if( m_cmd != NULL )
	{
		m_cmd->end();
		if( m_cmd->valid() )
		{
			kdDebug() << m_cmd->name() << endl;
		}
		delete m_cmd;
		m_cmd = NULL;
	}
}

void KKDoc::setName( const QString &name )
{
	terminate();
	m_cmd = new KKCmdName( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setName( name );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit nameChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setLocation( int* x, int* y )
{
	terminate();
	m_cmd = new KKCmdLocation( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setLocation( x == NULL ? item->location().x() : *x, y == NULL ? item->location().y() : *y );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit locationChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::moveStart()
{
	terminate();
	m_cmd = new KKCmdLocation( this );
	m_cmd->begin();
}

void KKDoc::moving()
{
	emit locationChanged();
}

void KKDoc::moveEnd()
{
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit locationChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setSize( int width, int height )
{
	terminate();
	m_cmd = new KKCmdSize( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setSize( width == -1 ? item->size().width() : width, height == -1 ? item->size().height() : height );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit sizeChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::resizeStart()
{
	terminate();
	m_cmd = new KKCmdSize( this );
	m_cmd->begin();
}

void KKDoc::resizing()
{
	emit sizeChanged();
}

void KKDoc::resizeEnd()
{
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit sizeChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setText( const QString &text )
{
	terminate();
	m_cmd = new KKCmdText( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setText( text );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit textChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setDataField( int datafield )
{
	terminate();
	m_cmd = new KKCmdDataField( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setDataField( datafield );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit datafieldChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setTextAlign( int align )
{
	terminate();
	m_cmd = new KKCmdTextAlign( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setTextAlign( align );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit textAlignChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setTextOrientation( Orientation orientation )
{
	terminate();
	m_cmd = new KKCmdTextOrientation( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setTextOrientation( orientation );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit textOrientationChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setTextColor( const QColor &color )
{
	terminate();
	m_cmd = new KKCmdTextColor( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setTextColor( color );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit textColorChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setTextFont( const QFont &font )
{
	terminate();
	m_cmd = new KKCmdTextFont( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setTextFont( font );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit textFontChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setImage( const QImage &i )
{
	terminate();
	m_cmd = new KKCmdImage( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setImage( i );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit imageChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setImagePrint( bool p )
{
	terminate();
	m_cmd = new KKCmdImagePrint( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setImagePrint( p );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit imagePrintChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setLocked( bool l )
{
	terminate();
	m_cmd = new KKCmdLocked( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setLocked( l );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit lockedChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::insert()
{
	terminate();
	m_cmd = new KKCmdInsert( this );
	m_cmd->begin();
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit inserted();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::remove()
{
	terminate();
	m_cmd = new KKCmdRemove( this );
	m_cmd->begin();
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, true );
		emit removed();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

void KKDoc::setOrientation( Orientation orientation )
{
	terminate();
	m_cmd = new KKCmdSize( this );
	m_cmd->begin();
	for( KKItem* item = m_cmd->items().first(); item; item = m_cmd->items().next() )
	{
		item->setOrientation( orientation );
	}
	m_cmd->end();
	if( m_cmd->valid() )
	{
		m_cmdHistory->addCommand( m_cmd, false );
		emit orientationChanged();
	}
	else
	{
		delete m_cmd;
	}
	m_cmd = NULL;
}

bool KKDoc::print( QPainter& p, const KKContactData *data )
{
	KKItem* item = (KKItem*)selectedItems().first();
	if( !item ) return false;
	if( item->parent() != NULL ) item = (KKItem*)item->parent();

	item->drawItem( p, 1, data );
	if( item->firstChild() )
	{
		printEach( item->firstChild(), p, data );
	}
	return true;
}

void KKDoc::printEach( QListViewItem* item, QPainter& p, const KKContactData *data )
{
	// To draw reverse order( lastChild to firstChild )
	QListViewItem* next = item->nextSibling();
	if( next ) printEach( next, p, data );
	((KKItem*)item)->drawItem( p, 1, data );
}

void KKDoc::cut()
{
	copy();
	remove();
}

void KKDoc::copy()
{
	m_clipboard.clear();
	QPtrList<QListViewItem> items = selectedItems();
	KKItem* item = (KKItem*)items.first();
	if( !item ) return;
	if( !item->parent() ) return;
	while( item )
	{
		KKItem* i = new KKItem( item->parent(), (KKItem*)item );
		m_clipboard.append( i );
		item->parent()->takeItem( i );
		item = (KKItem*)items.next();
	}
	m_actionCollection->action( "edit_paste" )->setEnabled( true );
}

void KKDoc::paste()
{
	KKItem* parent = (KKItem*)selectedItems().first();
	if( !parent ) return;
	if( parent->parent() ) parent = (KKItem*)parent->parent();
	clearSelection();
	for( KKItem* item = m_clipboard.first(); item; item = m_clipboard.next() )
	{
		KKItem* i = new KKItem( parent, item );
		i->setSelected( true );
		insertByCommand( parent, i );
	}
	insert();
	m_actionCollection->action( "edit_cut" )->setEnabled( true );
	m_actionCollection->action( "edit_copy" )->setEnabled( true );
}

void KKDoc::selectAll()
{
	QListViewItem* item = selectedItems().first();
	if( !item ) return;
	if( item->parent() )
	{
		item = item->parent();
	}
	else
	{
		setSelected( item, false );
	}
	if( item->firstChild() )
	{
		item = item->firstChild();
		while( item )
		{
			setSelected( item, true );
			item = item->nextSibling();
		}
	}
	else
	{
		setSelected( item, true );
	}
}

void KKDoc::raiseItem()
{
	QPtrList<QListViewItem> items = selectedItems();
	for( KKItem* item = (KKItem*)items.last(); item; item = (KKItem*)items.prev() )
	{
		QListViewItem* parent = item->parent();
		parent->takeItem( item );
		parent->insertItem( item );
		setSelected( item, true );
		item->slotRepaint();
	}
}

void KKDoc::lowerItem()
{
	QPtrList<QListViewItem> items = selectedItems();
	QListViewItem* bottom = items.last();
	for( KKItem* item = (KKItem*)items.first(); item; item = (KKItem*)items.next() )
	{
		while( bottom->nextSibling() )
		{
			bottom = bottom->nextSibling();
		}
		item->moveItem( bottom );
		setSelected( item, true );
		item->slotRepaint();
	}
}

void KKDoc::insertByCommand( QListViewItem* parent, KKItem* item )
{
	emit inserted( parent, item );
}

void KKDoc::removeByCommand( QListViewItem* parent, KKItem* item )
{
	emit removed( parent, item );
}

void KKDoc::setSelected( QListViewItem* item, bool selected )
{
	KListView::setSelected( item, selected );
	if( !item ) return;
	if( !selected ) return;
	if( childCount() != 2 ) return;
	if( item->parent() )
	{
		item = item->parent();
		setSelected( item, false );
	}
	bool bl = ( item == firstChild() );
	QListViewItem* other = ( bl ? item->nextSibling() : firstChild() );
	setOpen( item, true );
	setOpen( other, false );
	other = other->firstChild();
	while( other )
	{
		if( isSelected( other ) ) KListView::setSelected( other, false );
		other = other->nextSibling();
	}
}

void KKDoc::slotSelectionChanged()
{
	if( childCount() != 2 ) return;
	QListViewItem* item = selectedItems().first();
	if( !item ) return;

	m_actionCollection->action( "edit_cut" )->setEnabled( item->parent() );
	m_actionCollection->action( "edit_copy" )->setEnabled( item->parent() );
	m_actionCollection->action( "raise" )->setEnabled( item->parent() );
	m_actionCollection->action( "lower" )->setEnabled( item->parent() );

	if( item->parent() ) item = item->parent();
	bool bl = ( item == firstChild() );
	QListViewItem* other = ( bl ? item->nextSibling() : firstChild() );
	setOpen( item, true );
	setOpen( other, false );
	other = other->firstChild();
	while( other )
	{
		if( isSelected( other ) ) KListView::setSelected( other, false );
		other = other->nextSibling();
	}
}
