/////////////////////////////////////////////////////////////////////////////
// Name:        project.cc
// Purpose:     Data Designer Project
// Author:      Daniel Horak
// Modified by:
// RCS-ID:      $Id: project.cc,v 1.6 2004/01/04 18:32:16 horakdan Exp $
// Copyright:   (c) Daniel Horak
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWindows headers
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include <wx/splitter.h>
#include <wx/treectrl.h>
#include "config.h"
#include "project.h"
#include "container.h"
#include "schema.h"
#include "xml.h"
#include "objects/dbobject.h"
#include "objects/dbdomain.h"
#include "objects/dbentity.h"
#include "objects/dbview.h"
#include "objects/dbsequence.h"
#include "objects/dbrelation.h"
#include "objects/dbprocedure.h"
#include "objects/dbmodel.h"
#include "objects/dbproject.h"
#include "servers/dbserver.h"


BEGIN_EVENT_TABLE(DataDesignerProject, wxTreeCtrl)
	EVT_TREE_ITEM_RIGHT_CLICK(-1,	DataDesignerProject::OnItemRightClick)
	EVT_TREE_ITEM_ACTIVATED(-1,	DataDesignerProject::OnItemActivated)
	EVT_TREE_SEL_CHANGED(-1,	DataDesignerProject::OnItemSelected)
	EVT_TREE_BEGIN_LABEL_EDIT(-1,	DataDesignerProject::OnItemBeginLabelEdit)
	EVT_TREE_END_LABEL_EDIT(-1,	DataDesignerProject::OnItemEndLabelEdit)
	EVT_TREE_KEY_DOWN(-1,		DataDesignerProject::OnItemKeyDown)
END_EVENT_TABLE()

DataDesignerProject::DataDesignerProject(DataDesignerSplitter *splitter)
	: wxTreeCtrl(splitter, -1, wxDefaultPosition, wxDefaultSize,
	    wxTR_DEFAULT_STYLE | wxTR_EDIT_LABELS),
	    m_splitter(splitter), m_schema(NULL), m_initialized(FALSE),
	    m_server(NULL)
{
	m_dbproject	= new DBProject(this);
	m_projectid	= AddRoot(_("Project"), -1, -1, new DataDesignerItemData(m_dbproject));
	
	m_top_domains	= new DBDomainContainer	(this, AppendItem(m_projectid, _("Domains")));
	m_top_entities	= new DBEntityContainer	(this, AppendItem(m_projectid, _("Entities")));
	m_top_views	= new DBViewContainer	(this, AppendItem(m_projectid, _("Views")));
	m_top_sequences	= new DBSequenceContainer(this, AppendItem(m_projectid, _("Sequences")));
	m_top_relations	= new DBRelationContainer(this, AppendItem(m_projectid, _("Relations")));
	m_top_procedures= new DBProcedureContainer(this, AppendItem(m_projectid, _("Procedures")));
	m_top_models	= new DBModelContainer	(this, AppendItem(m_projectid, _("Models")));

	m_schemaid	= AppendItem(m_projectid, _("Schema"));
}

DataDesignerProject::~DataDesignerProject()
{
	delete m_top_domains;
	delete m_top_entities;
	delete m_top_views;
	delete m_top_sequences;
	delete m_top_relations;
	delete m_top_procedures;
	delete m_top_models;
}

bool DataDesignerProject::Open(wxInputStream& stream)
{
	wxXmlDocument	xmldoc;
	wxXmlNode	*root, *child;
	wxString	name;
	DBObject	*object;
	wxTreeItemId	parent;
	DataDesignerContainer	*top;

#ifdef ENABLE_DEBUG
	wxLogMessage("DataDesignerProject::Open()");
#endif

	if (xmldoc.Load(stream) == FALSE) {
		wxLogMessage("loading error");
		return FALSE;
	}
	
	root = xmldoc.GetRoot();
	if (root->GetName() != "datadesigner") {
		wxLogMessage(_("wrong top-level element '") + root->GetName() + "'");
	} else {
		child = root->GetChildren();
		while (child) {
			name = child->GetName();
			top = NULL;
			
			if (name == "domains") {
				top = m_top_domains;
			} else if (name == "entities") {
				top = m_top_entities;
			} else if (name == "views") {
				top = m_top_views;
			} else if (name == "sequences") {
				top = m_top_sequences;
			} else if (name == "relations") {
				top = m_top_relations;
			} else if (name == "procedures") {
				top = m_top_procedures;
			} else if (name == "models") {
				top = m_top_models;
			} else if (name == "project") {
				m_dbproject->LoadXmlNode(child);
				top = NULL;
			} else {
				wxLogMessage(_("unsupported element '") + name + "'");
			}
			
			if (top) {
				top->LoadXmlNode(child);
			}
			child = child->GetNext();
		}
		Expand(m_projectid);
		m_initialized = TRUE;
	}

	m_server = GetServerByName(m_dbproject->m_dbserver);
	if (m_server == NULL) {
		wxString msg;
		
		msg = _("Cannot find server '") + m_dbproject->m_dbserver + "'";
		wxMessageBox(msg, _("Error"), wxOK | wxICON_ERROR);
		
		DeleteAllObjects();
		return FALSE;
	}
	
	return TRUE;
}

bool DataDesignerProject::Save(wxOutputStream& stream)
{
	wxXmlDocument	xmldoc;
	wxXmlNode	*root;
	
#ifdef ENABLE_DEBUG
	wxLogMessage("DataDesignerProject::Save()");
#endif
	
	root = new wxXmlNode(wxXML_ELEMENT_NODE, "datadesigner");
	xmldoc.SetRoot(root);
	xmldoc.SetVersion("1.0");
	xmldoc.SetFileEncoding("UTF-8");

	root->AddChild(m_dbproject->GetXmlNode());
	
	root->AddChild(m_top_domains->GetXmlNode());
	root->AddChild(m_top_entities->GetXmlNode());
	root->AddChild(m_top_views->GetXmlNode());
	root->AddChild(m_top_sequences->GetXmlNode());
	root->AddChild(m_top_relations->GetXmlNode());
	root->AddChild(m_top_procedures->GetXmlNode());
	root->AddChild(m_top_models->GetXmlNode());

	if (! xmldoc.Save(stream)) {
		wxLogMessage("error during Save");
		return FALSE;
	}
	
	return TRUE;
}

void DataDesignerProject::DeleteAllObjects(void)
{
	DeleteChildren(m_top_domains->GetTreeItemId());
	DeleteChildren(m_top_entities->GetTreeItemId());
	DeleteChildren(m_top_views->GetTreeItemId());
	DeleteChildren(m_top_sequences->GetTreeItemId());
	DeleteChildren(m_top_relations->GetTreeItemId());
	DeleteChildren(m_top_procedures->GetTreeItemId());
	DeleteChildren(m_top_models->GetTreeItemId());

	Collapse(m_projectid);
	
	// clear also project's name, ...
	m_dbproject->m_name = wxEmptyString;
	m_dbproject->m_desc = wxEmptyString;
	
	if (m_schema) {
		delete m_schema;
		m_schema = NULL;
	}
	m_initialized = FALSE;
}

bool DataDesignerProject::NewObject(DataDesignerContainer *top)
{
	DBObject	*object = NULL;
	wxDialog	*editor;
	int		res;
	
	if (!top)
		return FALSE;

	object = top->CreateObject();
	if (!object)
		return FALSE;
	
	editor = object->Editor(FALSE);
	
	if (editor) {
		res = editor->ShowModal();
		editor->Destroy();
		
		if (res == wxID_OK) {
			object->AppendItem();
		} else {
			delete object;
		}
	}
	return TRUE;
}

void DataDesignerProject::OnItemRightClick(wxTreeEvent& event)
{
	wxTreeItemId	itemid;
	DataDesignerContainer	*top = NULL;
	
	if (! m_initialized) return;
	
	itemid = event.GetItem();
	
	if (itemid == m_top_domains->GetTreeItemId()) {
		top = m_top_domains;
	} else if (itemid == m_top_entities->GetTreeItemId()) {
		top = m_top_entities;
	} else if (itemid == m_top_views->GetTreeItemId()) {
		top = m_top_views;
	} else if (itemid == m_top_relations->GetTreeItemId()) {
		top = m_top_relations;
	} else if (itemid == m_top_procedures->GetTreeItemId()) {
		top = m_top_procedures;
	} else if (itemid == m_top_models->GetTreeItemId()) {
		top = m_top_models;
	} else if (itemid == m_top_sequences->GetTreeItemId()) {
		top = m_top_sequences;
	}
	
	if (top)
		NewObject(top);
}

void DataDesignerProject::OnItemActivated(wxTreeEvent& event)
{
	wxTreeItemId	itemid, parentid;
	wxDialog	*editor;
	DBObject	*object = NULL;
	
	itemid = event.GetItem();
	
	if (!m_initialized)
	{
		if (itemid == m_projectid)
		{
			editor = m_dbproject->Editor(FALSE);
			if (editor)
			{
				int res = editor->ShowModal();
				
				editor->Destroy();
				if (res == wxID_OK)
				{
					m_server = GetServerByName(m_dbproject->m_dbserver);
					
					if (m_server)
						m_initialized = TRUE;
					else
						wxLogMessage("Cannot find server '%s'", m_dbproject->m_dbserver.c_str());
				}
			}
		}
		return;
	}
	
	parentid = GetParent(itemid);

	if ((parentid == m_top_domains->GetTreeItemId()) ||
	    (parentid == m_top_entities->GetTreeItemId()) ||
	    (parentid == m_top_views->GetTreeItemId()) ||
	    (parentid == m_top_sequences->GetTreeItemId()) ||
	    (parentid == m_top_relations->GetTreeItemId()) ||
	    (parentid == m_top_procedures->GetTreeItemId()) ||
	    (parentid == m_top_models->GetTreeItemId()))
	{
		// parental item is a container, so item is a DB object
		object = ((DataDesignerItemData *)GetItemData(itemid))->GetObject();
		
		if (object) {
			editor = object->Editor(TRUE);
			if (editor) {
				editor->ShowModal();
				editor->Destroy();
			}
		}
	} else {	
		// parent is not a container
		if (itemid == m_projectid)
		{
			editor = m_dbproject->Editor(FALSE);
			if (editor)
			{
				editor->ShowModal();
				editor->Destroy();
			}
		}
	}
}

void DataDesignerProject::OnItemSelected(wxTreeEvent& event)
{
	wxTreeItemId	itemid;
	DataDesignerContainer	*top = NULL;
	
	if (! m_initialized) return;
	
	itemid = event.GetItem();

	if (itemid == m_top_domains->GetTreeItemId())
		top = m_top_domains;
	else if (itemid == m_top_entities->GetTreeItemId())
		top = m_top_entities;
	else if (itemid == m_top_views->GetTreeItemId())
		top = m_top_views;
	else if (itemid == m_top_sequences->GetTreeItemId())
		top = m_top_sequences;
	else if (itemid == m_top_relations->GetTreeItemId())
		top = m_top_relations;
	else if (itemid == m_top_procedures->GetTreeItemId())
		top = m_top_procedures;
	else if (itemid == m_top_models->GetTreeItemId())
		top = m_top_models;

	if (top)
	{
		// item is a container, so we will a list of all objects
		top->ShowList();
		m_schema = NULL;
	} else {
		wxWindow *win2;

		if (itemid == m_schemaid) {
			// item is the main schema
			m_schema = new DataDesignerGlobalSchema(m_splitter, this);
		}
		else
		{
			wxTreeItemId	parentid = GetParent(itemid);
			
			// check whether item is a model (its parent is m_top_models)
			if (parentid == m_top_models->GetTreeItemId()) {
				m_schema = new DataDesignerModelSchema(m_splitter, this,
					(DBModel *)(((DataDesignerItemData *)GetItemData(itemid))->GetObject()));
			}
		}
		if (m_schema) {
			m_schema->AddObjects();
			
			win2 = m_splitter->GetWindow2();
			if (win2 == m_schema) return;
			
			if (m_splitter->ReplaceWindow(win2, m_schema)) {
				m_schema->Show(TRUE);
				if (win2)
					win2->Destroy();
			}
		}
	}
}

void DataDesignerProject::OnItemBeginLabelEdit(wxTreeEvent& event)
{
	wxTreeItemId	itemid, parentid;
	DBObject	*object = NULL;
	
	if (! m_initialized) {
		event.Veto();
		return;
	}
	
	itemid = event.GetItem();
	parentid = GetParent(itemid);

	if ((parentid == m_top_domains->GetTreeItemId()) ||
	    (parentid == m_top_entities->GetTreeItemId()) ||
	    (parentid == m_top_views->GetTreeItemId()) ||
	    (parentid == m_top_sequences->GetTreeItemId()) ||
	    (parentid == m_top_relations->GetTreeItemId()) ||
	    (parentid == m_top_procedures->GetTreeItemId()) ||
	    (parentid == m_top_models->GetTreeItemId()))
	{
	} else {
		event.Veto();
	}
}

void DataDesignerProject::OnItemEndLabelEdit(wxTreeEvent& event)
{
	wxTreeItemId	itemid;
	DBObject	*object = NULL;
	
	if (! m_initialized) return;
	
	itemid = event.GetItem();

	object = ((DataDesignerItemData *)GetItemData(itemid))->GetObject();

	object->m_name = event.GetLabel();
}

void DataDesignerProject::OnItemKeyDown(wxTreeEvent& event)
{
	wxTreeItemId	itemid;
	DBObject	*object = NULL;
	
	if (! m_initialized) {
		event.Skip();
		return;
	}
	
	itemid = event.GetItem();

	object = ((DataDesignerItemData *)GetItemData(itemid))->GetObject();
	
	event.Skip();
}

void DataDesignerProject::SwapItems(wxTreeItemId item1, wxTreeItemId item2)
{
	DataDesignerItemData *itemdata1 = (DataDesignerItemData *)GetItemData(item1);
	DataDesignerItemData *itemdata2 = (DataDesignerItemData *)GetItemData(item2);

	DBObject	*object1 = itemdata1->GetObject();
	DBObject	*object2 = itemdata2->GetObject();
	
	itemdata1->SetObject(object2);
	itemdata2->SetObject(object1);
	
	SetItemText(item1, object2->m_name);
	SetItemText(item2, object1->m_name);
	
	object1->SetTreeItemId(item2);
	object2->SetTreeItemId(item1);
}


syntax highlighted by Code2HTML, v. 0.9.1