// -*- C++ -*-

/* 
 * GChemPaint library
 * fragment-atom.cc 
 *
 * Copyright (C) 2003-2005 Jean Bréfort <jean.brefort@normalesup.org>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "gchempaint-config.h"
#include "fragment-atom.h"
#include "fragment.h"
#include "molecule.h"
#include <gcu/element.h>
#include <cstring>

gcpFragmentAtom::gcpFragmentAtom(): gcpAtom()
{
	SetId ((char*) "a1");
}

gcpFragmentAtom::gcpFragmentAtom(gcpFragment *fragment, int Z): gcpAtom()
{
	m_Fragment = fragment;
	SetZ(Z);
	SetId ((char*) "a1");
}

gcpFragmentAtom::~gcpFragmentAtom() {}

void gcpFragmentAtom::SetZ(int Z)
{
	static bool setting = false;
	if (setting) return;
	setting = true;
	Atom::SetZ(Z);
	if (Z != 0) m_Fragment->OnChangeAtom();
	setting = false;
}

/*!
Only accept a new bond if none exists. So only one bond.
*/
bool gcpFragmentAtom::AcceptNewBonds(int nb)
{
	return (nb > 1)? false: GetBondsNumber() == 0;
}

/*!
Overrided to avoid gcpAtom::Add execution. Don't do anything.
*/
void gcpFragmentAtom::Add(GtkWidget* w)
{
}

/*!
Overrided to avoid gcpAtom::Update execution. Just call fragment Update method.
*/
void gcpFragmentAtom::Update(GtkWidget* w)
{
	m_Fragment->Update(w);
}


/*!
Overrided to avoid gcpAtom::SetSelected execution. Just call fragment SetSelected method.
*/
void gcpFragmentAtom::SetSelected(GtkWidget* w, int state)
{
	m_Fragment->SetSelected(w, state);
}

xmlNodePtr gcpFragmentAtom::Save(xmlDocPtr xml)
{
	xmlNodePtr node;
	gchar buf[16];
	node = xmlNewDocNode(xml, NULL, (xmlChar*)"atom", NULL);
	if (!node) return NULL;
	SaveId(node);

	strncpy(buf, GetSymbol(), sizeof(buf));
	xmlNodeSetContent(node, (xmlChar*)buf);
	
	if (m_Charge)
	{
		snprintf(buf, sizeof(buf), "%d", m_Charge);
		xmlNewProp(node, (xmlChar*)"charge", (xmlChar*)buf);
		double Angle, Dist;
		unsigned char ChargePos = gcpAtom::GetChargePosition (&Angle, &Dist);
		if (ChargePos != 0xff) {
			char *buf;
			if (ChargePos) {
				switch (ChargePos) {
				case CHARGE_NE:
					buf = (char*) "ne";
					break;
				case CHARGE_NW:
					buf = (char*) "nw";
					break;
				case CHARGE_N:
					buf = (char*) "n";
					break;
				case CHARGE_SE:
					buf = (char*) "se";
					break;
				case CHARGE_SW:
					buf = (char*) "sw";
					break;
				case CHARGE_S:
					buf= (char*) "s";
					break;
				case CHARGE_E:
					buf = (char*) "e";
					break;
				case CHARGE_W:
					buf = (char*) "w";
					break;
				default:
					buf = (char*) "def"; // should not occur
				}
				xmlNewProp (node, (xmlChar*) "charge-position", (xmlChar*) buf);
			} else {
				buf = g_strdup_printf ("%g", Angle * 180. / M_PI);
				xmlNewProp (node, (xmlChar*) "charge-angle", (xmlChar*) buf);
				g_free (buf);
			}
			if (Dist != 0.) {
				buf = g_strdup_printf ("%g", Dist);
				xmlNewProp (node, (xmlChar*) "charge-dist", (xmlChar*) buf);
				g_free (buf);
			}
		}
	}
	return node;
}

bool gcpFragmentAtom::Load (xmlNodePtr node)
{
	char* buf;
	unsigned char ChargePos = 0xff;
	double Angle = 0., Dist = 0.;
	buf = (char*) xmlGetProp (node, (xmlChar*) "id");
	if (buf) {
		SetId (buf);
		xmlFree (buf);
	}
	buf = (char*) xmlNodeGetContent (node);
	if (buf) {
		m_Z = Element::Z (buf);
		xmlFree (buf);
	}
	buf = (char*) xmlGetProp (node, (xmlChar*) "charge");
	m_Charge = (buf)? (char) atoi (buf): 0;
	if (buf)
		xmlFree (buf);
	if (m_Charge) {
		char *buf = (char*) xmlGetProp (node, (xmlChar*) "charge-position");
		if (buf) {
			if (! strcmp (buf, "ne")) {
				ChargePos = CHARGE_NE;
				Angle = M_PI / 4.;
			} else if (! strcmp (buf, "nw")) {
				ChargePos = CHARGE_NW;
				Angle = 3. * M_PI / 4.;
			} else if (! strcmp (buf, "n")) {
				ChargePos = CHARGE_N;
				Angle = M_PI / 2.;
			} else if (! strcmp (buf, "se")) {
				ChargePos = CHARGE_SE;
				Angle = 7. * M_PI / 4;
			} else if (! strcmp (buf, "sw")) {
				ChargePos = CHARGE_SW;
				Angle = 5. * M_PI / 4;
			} else if (! strcmp (buf, "s")) {
				ChargePos = CHARGE_S;
				Angle = 3 * M_PI / 2.;
			} else if (! strcmp (buf, "e")) {
				ChargePos = CHARGE_E;
				Angle = 0.;
			} else if (! strcmp (buf, "w")) {
				ChargePos = CHARGE_W;
				Angle = M_PI;
			}
			xmlFree (buf);
		} else {
			buf = (char*) xmlGetProp (node, (xmlChar*)"charge-angle");
			if (buf) {
				sscanf (buf, "%lg", &Angle);
				Angle *= M_PI / 180.;
				xmlFree (buf);
				ChargePos = 0;
			}
		}
		buf = (char*) xmlGetProp (node, (xmlChar*)"charge-dist");
		if (buf) {
			sscanf (buf, "%lg", &Dist);
			xmlFree (buf);
		}
		SetChargePosition (ChargePos, ChargePos == 0xff, Angle, Dist);
	}
	return true;
}

void gcpFragmentAtom::AddToMolecule(gcpMolecule* Mol)
{
	Mol->AddFragment(m_Fragment);
}

int gcpFragmentAtom::GetChargePosition(unsigned char& Pos, double Angle, double& x, double& y)
{
	return m_Fragment->GetChargePosition(this, Pos, Angle, x, y);
}


int gcpFragmentAtom::GetAvailablePosition(double& x, double& y)
{
	return m_Fragment->GetAvailablePosition(x, y);
}
	
bool gcpFragmentAtom::GetPosition(double angle, double& x, double& y)
{
	return m_Fragment->GetPosition(angle, x, y);
}
	
bool gcpFragmentAtom::AcceptCharge (int charge) {
	return (charge >= -1 && charge <= 1);
}

void gcpFragmentAtom::Update()
{
}


syntax highlighted by Code2HTML, v. 0.9.1