/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */
#include "apache/das/rdb/Relationship.h"

namespace apache {
	namespace das {
		namespace rdb {

Relationship::Relationship(const Relationship& relationship) {
	many = relationship.many;
	relationshipName = relationship.relationshipName;
	pkTableName = relationship.pkTableName;
	fkTableName = relationship.fkTableName;
	this->keyPairs = new std::map<std::string, const KeyPair*>();
	
	std::map<std::string, const KeyPair*>::iterator it;
	for (it = relationship.keyPairs->begin() ; it != relationship.keyPairs->end() ; it++) {
		KeyPair* newKP = new KeyPair(*it->second);
		newKP->setRelationship(this);
		this->keyPairs->insert(std::make_pair(it->first, newKP));
		
	}

}

Relationship::Relationship(std::string pkTableName, std::string fkTableName, 
						   std::string relationshipName) {

    StringWrapper pkTableNameWrapper(pkTableName);
	StringWrapper fkTableNameWrapper(fkTableName);
	StringWrapper relationshipNameWrapper(relationshipName);
    pkTableName = pkTableNameWrapper.toUpper();
	fkTableName = fkTableNameWrapper.toUpper();

    if (relationshipName == "") {
		this->relationshipName = fkTableName;
    } else {

		if (!relationshipNameWrapper.isValidRDBName()) {
			throw DASInvalidRelationshipNameException("Relationship name must not contain whitespace characters!");
		}

		this->relationshipName = relationshipNameWrapper.toUpper();

    }

	if (!pkTableNameWrapper.isValidRDBName()) {
		throw DASInvalidTableNameException("PK Table name must not contain whitespace characters!");
	}

	if (!fkTableNameWrapper.isValidRDBName()) {
		throw DASInvalidTableNameException("FK Table name must not contain whitespace characters!");
	}

	this->pkTableName = pkTableName;
	this->fkTableName = fkTableName;
	many = true;
	keyPairs = new std::map<std::string, const KeyPair*>();

}

void Relationship::setMany(bool many) {
	this->many = many;
}

bool Relationship::isMany(void) const {
	return many;
}

KeyPair& Relationship::addKeyPair(std::string pkColumnName, std::string fkColumnName) {
	KeyPair& newKP = newKeyPair(*(new KeyPair(pkColumnName, fkColumnName)));
	newKP.setRelationship(this);

	return newKP;

}

KeyPair& Relationship::addKeyPair(const KeyPair& keyPair) {
	KeyPair& newKP = newKeyPair(*(new KeyPair(keyPair)));
	newKP.setRelationship(this);

	return newKP;

}

KeyPair& Relationship::newKeyPair(KeyPair& keyPair) {
	const KeyPair* configKeyPair = getKeyPair(keyPair.getPKColumnName(), keyPair.getFKColumnName());

	if (configKeyPair == 0) {
		keyPairs->insert(std::make_pair(keyPair.getPKColumnName() + "." + keyPair.getFKColumnName(), &keyPair));

		return keyPair;

	}

	return (KeyPair&) *configKeyPair;

}

std::string Relationship::getName(void) const {
	return relationshipName;
}

Relationship::~Relationship(void) {
	std::map<std::string, const KeyPair*>::iterator it;

	for (it = keyPairs->begin() ; it != keyPairs->end() ; it++) {
		delete it->second;
	}

	delete keyPairs;

}

std::string Relationship::getPKTableName(void) const {
	return pkTableName;
}

std::string Relationship::getFKTableName(void) const {
	return fkTableName;
}

const std::map<std::string, const KeyPair*>& Relationship::getKeyPairs(void) const {
	return (const std::map<std::string, const KeyPair*>&) *keyPairs;
}

const KeyPair* Relationship::getKeyPair(std::string pkColumnName, std::string fkColumnName) const {
	std::map<std::string, const KeyPair*>::iterator it = keyPairs->
		find(pkColumnName + "." + fkColumnName);

	if (it == keyPairs->end()) {
		return 0;
	}

	return it->second;

}

std::list<const KeyPair*>* Relationship::getKeyPair(std::string columnName, bool pkColumn) const {
	std::map<std::string, const KeyPair*>::const_iterator it;
	std::list<const KeyPair*>* ret = new std::list<const KeyPair*>();

	for (it = keyPairs->begin() ; it != keyPairs->end() ; it++) {
		std::string actualColumnName;

		if (pkColumn) {
			actualColumnName = it->second->getPKColumnName();
		} else {
			actualColumnName = it->second->getFKColumnName();
		}

		if (columnName == actualColumnName) {
			ret->push_back(it->second);
		}

	}

	return ret;

}


bool Relationship::containsColumn(std::string columnName, bool pkColumn) const {
	std::map<std::string, const KeyPair*>::const_iterator it;	

	for (it = keyPairs->begin() ; it != keyPairs->end() ; it++) {

		if (pkColumn) {

			if (it->second->getPKColumnName() == columnName) {
				return true;
			}

		} else {

			if (it->second->getFKColumnName() == columnName) {
				return true;
			}

		}

	}

	return false;

}

		};
	};
};
