/////////////////////////////////////////////////////////////////////////////
// Name:        dbattribute.cc
// Purpose:     Database Objects
// Author:      Daniel Horak
// Modified by:
// RCS-ID:      $Id: dbattribute.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/ogl/ogl.h>
#include "config.h"
#include "xml.h"
#include "dbobject.h"
#include "dbattribute.h"
#include "dbsimpleattr.h"
#include "dbentity.h"
#include "servers/dbserver.h"
#include "schema.h"

#define	ID_PRIMARYKEY	10
#define	ID_GENERATED	11


DBAttribute::DBAttribute(DataDesignerProject *project, DataDesignerContainer *container)
	:DBObject(DBAttributeType, "attribute", project, container), m_nullable(FALSE),
	    m_unique(FALSE), m_primarykey(FALSE), m_foreignkey(FALSE), m_array(FALSE),
	    m_generated(FALSE), m_imported(FALSE)
{
}

DBAttribute::~DBAttribute()
{
	wxDBObjectListNode	*node;
	
	// must delete all simpleattrs derived from this real attr
	node = m_simpleattrs.GetFirst();
	while (node) {
		delete node->GetData();
		node = node->GetNext();
	}
}

wxDialog *DBAttribute::Editor(bool edit)
{
	return new DBAttributeEditor(this, edit);
}

void DBAttribute::LoadXmlNode(wxXmlNode *node)
{
	if (node->GetName() == m_typestr) {
		DBObject::LoadXmlNode(node);
	
		m_type		= node->GetPropVal("type", wxEmptyString);
		m_length	= node->GetPropVal("length", wxEmptyString);
		m_decimals	= node->GetPropVal("decimals", wxEmptyString);
		LoadBoolProperty(node, "nullable", m_nullable);
		LoadBoolProperty(node, "unique", m_unique);
		LoadBoolProperty(node, "primarykey", m_primarykey);
		LoadBoolProperty(node, "foreignkey", m_foreignkey);
		LoadBoolProperty(node, "array", m_array);
		LoadBoolProperty(node, "generated", m_generated);
		m_default	= node->GetPropVal("default", wxEmptyString);
		m_check		= node->GetPropVal("check", wxEmptyString);
		LoadBoolProperty(node, "imported", m_imported);
		m_relation	= node->GetPropVal("relation", wxEmptyString);
		
		wxXmlNode *child = node->GetChildren();
		wxString name;
		while (child) {
			name = child->GetName();
			if (name == "type")
				LoadTextNode(child, "type", m_type);
			else if (name == "length")
				LoadTextNode(child, "length", m_length);
			else if (name == "decimals")
				LoadTextNode(child, "decimals", m_decimals);
			else if (name == "nullable")
				LoadBoolNode(child, "nullable", m_nullable);
			else if (name == "unique")
				LoadBoolNode(child, "unique", m_unique);
			else if (name == "primarykey")
				LoadBoolNode(child, "primarykey", m_primarykey);
			else if (name == "foreignkey")
				LoadBoolNode(child, "foreignkey", m_foreignkey);
			else if (name == "array")
				LoadBoolNode(child, "array", m_array);
			else if (name == "generated")
				LoadBoolNode(child, "generated", m_generated);
			else if (name == "default")
				LoadTextNode(child, "default", m_default);
			else if (name == "check")
				LoadTextNode(child, "check", m_check);
			else if (name == "imported")
				LoadBoolNode(child, "imported", m_imported);
			else if (name == "relation")
				LoadTextNode(child, "relation", m_relation);
			child = child->GetNext();
		}
	} else {
		wxLogMessage("wrong type '%s'", node->GetName().c_str());
	}
	
	// set pointer to the real attribute
}

wxXmlNode *DBAttribute::GetXmlNode()
{
	wxXmlNode *node = DBObject::GetXmlNode();
	
	node->AddChild(GetTextNode("type", m_type));
	node->AddChild(GetTextNode("length", m_length));
	node->AddChild(GetTextNode("decimals", m_decimals));
	node->AddChild(GetBoolNode("nullable", m_nullable));
	node->AddChild(GetBoolNode("unique", m_unique));
	node->AddChild(GetBoolNode("primarykey", m_primarykey));
	node->AddChild(GetBoolNode("foreignkey", m_foreignkey));
	node->AddChild(GetBoolNode("array", m_array));
	node->AddChild(GetBoolNode("generated", m_generated));
	node->AddChild(GetTextNode("default", m_default));
	node->AddChild(GetTextNode("check", m_check));
	node->AddChild(GetBoolNode("imported", m_imported));
	node->AddChild(GetTextNode("relation", m_relation));
	
	return node;
}

void DBAttribute::AddSimpleAttribute(DBSimpleAttribute *attr)
{
#ifdef ENABLE_DEBUG
	wxLogMessage("DBAttribute::AddSimpleAttribute - count=%d, attr=%p", m_simpleattrs.GetCount(), attr);
#endif
	
	m_simpleattrs.Append(attr);
}

void DBAttribute::DeleteSimpleAttribute(DBSimpleAttribute *attr)
{
#ifdef ENABLE_DEBUG
	wxLogMessage("DBAttribute::DeleteSimpleAttribute - count=%d, attr=%p", m_simpleattrs.GetCount(), attr);
#endif
	
	if (m_simpleattrs.IndexOf(attr) != wxNOT_FOUND) {
		m_simpleattrs.DeleteObject(attr);
	}
}

void DBAttribute::Copy(DBAttribute *attr)
{
	if (attr == NULL)
		return;
	
	m_name		= attr->m_name;
	m_pname		= attr->m_pname;
	m_type		= attr->m_type;
	m_length	= attr->m_length;
	m_decimals	= attr->m_decimals;
	m_nullable	= attr->m_nullable;
	m_unique	= attr->m_unique;
	m_array		= attr->m_array;
	m_generated	= attr->m_generated;
	m_default	= attr->m_default;
	m_check		= attr->m_check;
}

DBEntity *DBAttribute::GetEntity()
{
	DBEntity	*entity;
	wxTreeItemId	treeid;
	
	treeid = GetContainer()->GetTreeItemId();	// list of this attr
	treeid = GetProject()->GetParent(treeid);	// entity
	entity = (DBEntity *)(((DataDesignerItemData *)(GetProject()->GetItemData(treeid)))->GetObject());
	
	return (entity->GetType() == DBEntityType) ? entity : NULL;
}

/*
 * Editor
 */
BEGIN_EVENT_TABLE(DBAttributeEditor, DBObjectEditor)
	EVT_CHECKBOX(-1,	DBAttributeEditor::OnCheckBox)
END_EVENT_TABLE()

DBAttributeEditor::DBAttributeEditor(DBObject *object, bool edit)
	: DBObjectEditor(_("Attribute"), wxSize(500,300), object, edit)
{
	wxString	**strings;
	int		idx;
	DataDesignerProject	*project;
	
	idx = 0;
	project = GetObject()->GetProject();
	strings = project->m_top_domains->ListNames();
	
	new wxStaticText(m_page_general, -1, _("Type"), wxPoint(10,60), wxSize(80,-1), wxALIGN_RIGHT);
	c1 = new wxComboBox(m_page_general, -1, wxEmptyString, wxPoint(100,60), wxSize(150,-1),
		project->GetServer()->GetTypesCount(), project->GetServer()->GetTypes(), wxCB_SORT);
	while (strings[idx]) {
		c1->Append(*strings[idx]);
		idx++;
	}
	delete strings;

	new wxStaticText(m_page_general, -1, _("Length"), wxPoint(10,85), wxSize(80,-1), wxALIGN_RIGHT);
	t2 = new wxTextCtrl(m_page_general, -1, wxEmptyString, wxPoint(100,85), wxSize(50,-1));

	new wxStaticText(m_page_general, -1, _("Decimals"), wxPoint(160,85), wxSize(130,-1), wxALIGN_RIGHT);
	t3 = new wxTextCtrl(m_page_general, -1, wxEmptyString, wxPoint(300,85), wxSize(50,-1));
	
	c4 = new wxCheckBox(m_page_general, -1, _("Nullable"), wxPoint(10,110), wxSize(80,-1));
	c5 = new wxCheckBox(m_page_general, ID_PRIMARYKEY, _("Primary Key"), wxPoint(100,110), wxSize(100,-1));
	c8 = new wxCheckBox(m_page_general, -1, _("Unique"), wxPoint(210,110), wxSize(80,-1));
	c9 = new wxCheckBox(m_page_general, -1, _("Array"), wxPoint(300,110), wxSize(80,-1));
	c10 = new wxCheckBox(m_page_general, ID_GENERATED, _("Generated"), wxPoint(400,110), wxSize(80,-1));

	new wxStaticText(m_page_general, -1, _("Default"), wxPoint(10,135), wxSize(80,-1), wxALIGN_RIGHT);
	t6 = new wxTextCtrl(m_page_general, -1, wxEmptyString, wxPoint(100,135), wxSize(100,-1));

	new wxStaticText(m_page_general, -1, _("Check"), wxPoint(210,135), wxSize(80,-1), wxALIGN_RIGHT);
	t7 = new wxTextCtrl(m_page_general, -1, wxEmptyString, wxPoint(300,135), wxSize(170,-1));
}

DBAttributeEditor::~DBAttributeEditor()
{
}

bool DBAttributeEditor::TransferDataFromWindow()
{
	DBAttribute	*object = (DBAttribute *)GetObject();

	DBObjectEditor::TransferDataFromWindow();

	object->m_type 		= c1->GetValue();
	object->m_length 	= t2->GetValue();
	object->m_decimals	= t3->GetValue();
	object->m_nullable	= c4->GetValue();
	object->m_primarykey	= c5->GetValue();
	object->m_default	= t6->GetValue();
	object->m_check		= t7->GetValue();
	object->m_unique	= c8->GetValue();
	object->m_array		= c9->GetValue();
	object->m_generated	= c10->GetValue();
	
	return TRUE;
}

bool DBAttributeEditor::TransferDataToWindow()
{
	DBAttribute	*object = (DBAttribute *)GetObject();
	
	DBObjectEditor::TransferDataToWindow();

	c1->SetValue(object->m_type);
	t2->SetValue(object->m_length);
	t3->SetValue(object->m_decimals);
	c4->SetValue(object->m_nullable);
	c5->SetValue(object->m_primarykey);
	t6->SetValue(object->m_default);
	t7->SetValue(object->m_check);
	c8->SetValue(object->m_unique);
	c9->SetValue(object->m_array);
	c10->SetValue(object->m_generated);
	
	return TRUE;
}

void DBAttributeEditor::OnCheckBox(wxCommandEvent& event)
{
	DBEntity	*entity;
	DBObject	*seq;
	
#ifdef ENABLE_DEBUG
	wxLogMessage("DBAttributeEditor::OnCheckBox");
#endif
	
	entity = ((DBAttribute *)GetObject())->GetEntity();
	if (entity == NULL) {
		wxLogMessage("DBAttributeEditor::OnCheckBox - entity == NULL");
		return;
	}
	
//	GetObject()->m_name = it1->GetValue();
	if (TransferDataFromWindow() == FALSE) {
		event.Skip();
		return;
	}

	switch (event.GetId()) {
		case ID_PRIMARYKEY:
#ifdef ENABLE_DEBUG
			wxLogMessage("primary key");
#endif
			if (c5->GetValue() == TRUE)
				entity->AddAttributeToPrimaryKey((DBAttribute *)GetObject());
			else
				entity->DeleteAttributeFromPrimaryKey((DBAttribute *)GetObject());
			break;
			
		case ID_GENERATED:
#ifdef ENABLE_DEBUG
			wxLogMessage("generated");
#endif
			seq = GetObject()->GetProject()->m_top_sequences->GetObjectByName(entity->m_name + "_seq");
			if (c10->GetValue() == TRUE) {
				// create sequence iff not exist
				if (seq == NULL) {
					seq = GetObject()->GetProject()->m_top_sequences->CreateObject();
					seq->m_name = entity->m_name + "_seq";
					seq->m_pname = seq->m_name;
					seq->AppendItem();
				}
			} else {
				// delete sequence iff exist
				if (seq)
					delete seq;
			}
			break;
			
		default:
			event.Skip();
			break;
	}
}

bool DBAttributeEditor::Validate()
{
	bool res = DBObjectEditor::Validate();
	
	if (res == FALSE)
		return res;
	
	// generated & default cannot be specified in one time
	if (c10->GetValue() && ! t6->GetValue().IsEmpty()) {
		wxMessageBox(_("Generated and Default cannot be specified together"), _("Error"), wxOK | wxICON_ERROR);
		return FALSE;
	}
	
	return TRUE;
}

/*
 * Container
 */
DBAttributeContainer::DBAttributeContainer(DataDesignerProject *project, const wxTreeItemId& parent)
	: DataDesignerContainer(project, parent, "attributes")
{
}

DBObject *DBAttributeContainer::CreateObject()
{
	return new DBAttribute(GetProject(), this);
}

void DBAttributeContainer::ShowList()
{
	SetList(new DBAttributeListCtrl(GetProject()->GetSplitter(), this));
	
	DataDesignerContainer::AddObjectsToListAndShow();
}

/*
 * ObjectList
 */
BEGIN_EVENT_TABLE(DBAttributeListCtrl, DBObjectListCtrl)
	EVT_BUTTON(ID_BUTTON_DELETE,	DBAttributeListCtrl::OnDelete)
END_EVENT_TABLE()

DBAttributeListCtrl::DBAttributeListCtrl(wxWindow *parent, DataDesignerContainer *container)
	: DBObjectListCtrl(parent, container)
{
	InsertColumn(1, _("Type"));
	InsertColumn(2, _("Length"));
	InsertColumn(3, _("Decimals"));
	InsertColumn(4, _("Nullable"));
	InsertColumn(5, _("Primary"));
	InsertColumn(6, _("Unique"));
	InsertColumn(7, _("Default"));

	SetColumnWidth(4, 50);
	SetColumnWidth(5, 50);
	SetColumnWidth(6, 50);
}

DBAttributeListCtrl::~DBAttributeListCtrl()
{
}

void DBAttributeListCtrl::SetObject(long item, DBObject *object)
{
	DBAttribute *attribute = (DBAttribute *)object;

#ifdef ENABLE_DEBUG
	wxLogMessage("DBAttributeListCtrl::SetObject");
#endif
	
	SetItem(item, 1, attribute->m_type);
	SetItem(item, 2, attribute->m_length);
	SetItem(item, 3, attribute->m_decimals);
	SetItem(item, 4, BOOL2STR(attribute->m_nullable));
	SetItem(item, 5, BOOL2STR(attribute->m_primarykey));
	SetItem(item, 6, BOOL2STR(attribute->m_unique));
	SetItem(item, 7, attribute->m_default);
}

void DBAttributeListCtrl::OnDelete(wxCommandEvent& event)
{
	DBAttribute	*attr;
	
#ifdef ENABLE_DEBUG
	wxLogMessage("DBAttributeListCtrl::OnDelete - m_current=%ld", m_current);
#endif

	if (m_current == -1)
		return;

	attr = (DBAttribute *)m_list->GetItemData(m_current);
	if (attr && (attr->m_imported == TRUE)) {
#ifdef ENABLE_DEBUG
		wxLogMessage("DBAttributeListCtrl::OnDelete - cannot delete imported attr");
#endif
	} else {
		// use generic OnDelete from DBObjectListCtrl
		event.Skip();
	}
}


syntax highlighted by Code2HTML, v. 0.9.1