/*
    Copyright 2011  Andi Fischer  <andi.fischer@hispeed.ch>

    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) version 3 or any later version
    accepted by the membership of KDE e.V. (or its successor approved
    by the membership of KDE e.V.), which shall act as a proxy 
    defined in Section 14 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "testclassifier.h"

// app include
#include "uml.h"
#include "association.h"
#include "classifier.h"
#include "datatype.h"
#include "operation.h"
#include "model_utils.h"

//-----------------------------------------------------------------------------

void TEST_classifier::test_equal()
{
    UMLClassifier* a = new UMLClassifier("Test A", Uml::ID::None);
    UMLClassifier* b = a;
    UMLClassifier* c = new UMLClassifier("Test A", Uml::ID::None);
    UMLClassifier* d = new UMLClassifier("Test B", Uml::ID::None);
    QCOMPARE(*a == *b, true);
    QCOMPARE(*a == *c, true);
    QCOMPARE(*b == *c, true);
    QCOMPARE(*c == *d, false);
}

void TEST_classifier::test_copyInto()
{
    UMLClassifier a("Test A", Uml::ID::None);
    UMLClassifier b("Test B", Uml::ID::None);
    b.copyInto(&a);
    QCOMPARE(a == b, true);
}

void TEST_classifier::test_clone()
{
    UMLClassifier* a = new UMLClassifier("Test A", Uml::ID::None);
    UMLClassifier* b = a->clone()->asUMLClassifier();
    QCOMPARE(*a == *b, true);
}

void TEST_classifier::test_addAttributeWithType()
{
    UMLClassifier a("Test A", Uml::ID::None);
    a.addAttribute("attributeA_", Uml::ID::None);
    UMLAttribute *attrA = a.addAttribute("attributeA_", Uml::ID::None);
    /* UMLAttribute* attrB = */ a.addAttribute("attributeB_", Uml::ID::None);
    int num1 = a.getAttributeList().count();
    QCOMPARE(num1, 2);
    int num2 = a.removeAttribute(attrA);
    QCOMPARE(num2, 1);  // one deleted
    int num3 = a.getAttributeList().count();
    QCOMPARE(num3, num1 - 1);
}

void TEST_classifier::test_addAttributeWithObject()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_addAttributeWithAttribute()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_removeAndCountAttribute()
{
    UMLClassifier* a = new UMLClassifier("Test A", Uml::ID::None);
    int num0 = a->getAttributeList().count();
    QCOMPARE(num0, 0);  // no attributes present yet
    /*UMLAttribute* attrA = */ a->addAttribute("attributeA_", Uml::ID::None);
    UMLAttribute* attrB = a->addAttribute("attributeB_", Uml::ID::None);
    UMLAttribute* attrC = a->addAttribute("attributeC_", Uml::ID::None);
    /* UMLAttribute* attrD = */ a->addAttribute("attributeD_", Uml::ID::None);
    int num1 = a->getAttributeList().count();
    QCOMPARE(num1, 4);
    int num2 = a->removeAttribute(attrB);
    QCOMPARE(num2, 3);  // one deleted
    num2 = a->removeAttribute(attrC);
    QCOMPARE(num2, 2);  // one deleted
    int num3 = a->getAttributeList().count();
    QCOMPARE(num3, 2); 
}

void TEST_classifier::test_getAttributeList()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_addOperationWithPosition()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_addOperationWithLog()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_checkOperationSignature()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_removeAndCountOperation()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_getOperationList()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_addTemplateWithType()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_addTemplateWithLog()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_addTemplateWithPosition()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_removeAndCountTemplate()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_findTemplate()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_getTemplateList()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_takeItem()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_getFilteredList()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_resolveRef()
{
    qDebug() << "already tested by testumlobject";
}

void TEST_classifier::test_findOperations()
{
    UMLClassifier c("Test A", Uml::ID::None);
    UMLOperation o1(nullptr, "testop1");
    c.addOperation(&o1);
    int num1 = c.getOpList().count();
    QCOMPARE(num1, 1);
    UMLOperation o2(nullptr, "testop2");
    c.addOperation(&o2);
    int num2 = c.getOpList().count();
    QCOMPARE(num2, 2);
    QCOMPARE(c.findOperations("testop1").count(), 1);
    QCOMPARE(c.findOperations("testop2").count(), 1);
    QCOMPARE(c.findOperations("testOp1").count(), 0);
    QCOMPARE(c.findOperations("testOp2").count(), 0);
    // case insensitive language
    Uml::ProgrammingLanguage::Enum lang = UMLApp::app()->activeLanguage();
    UMLApp::app()->setActiveLanguage(Uml::ProgrammingLanguage::PostgreSQL);
    QCOMPARE(c.findOperations("testOp1").count(), 1);
    QCOMPARE(c.findOperations("testOp2").count(), 1);
    UMLApp::app()->setActiveLanguage(lang);
}

void TEST_classifier::test_findChildObjectById()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_findOperation()
{
    UMLClassifier c("Test A", Uml::ID::None);
    UMLOperation o1(nullptr, "testop1");
    UMLAttribute a1(nullptr, "aParam");
    a1.setTypeName("int");
    o1.addParm(&a1);
    c.addOperation(&o1);
    UMLOperation o2(nullptr, "testop1");
    UMLAttribute a2(nullptr, "aParam");
    a2.setTypeName("double");
    o2.addParm(&a2);
    c.addOperation(&o2);
    Model_Utils::NameAndType_List searchTypes;
    // first function
    searchTypes << Model_Utils::NameAndType("aParam", a1.getType());
    UMLOperation *o = c.findOperation("testop1", searchTypes);
    QVERIFY(o);
    // second function
    searchTypes.clear();
    searchTypes << Model_Utils::NameAndType("aParam", a2.getType());
    o = c.findOperation("testop1", searchTypes);
    QVERIFY(o);

    // unknown type
    UMLDatatype d1("someType");
    searchTypes.clear();
    searchTypes << Model_Utils::NameAndType("aParam", &d1);
    o = c.findOperation("testop1", searchTypes);
    QVERIFY(!o);

#if 0
    // different param name
    searchTypes.clear();
    searchTypes << Model_Utils::NameAndType("otherParam", a1.getType());
    o = c.findOperation("testop1", searchTypes);
    QVERIFY(!o);

    // different param name
    searchTypes.clear();
    searchTypes << Model_Utils::NameAndType("otherParam", a2.getType());
    o = c.findOperation("testop1", searchTypes);
    QVERIFY(!o);
#else
    qDebug() <<"finding param names is not supported";
#endif
}

void TEST_classifier::test_findSuperClassConcepts()
{
    UMLClassifier c1("Test A");
    UMLClassifier c2("Test B");
    UMLAssociation a1(Uml::AssociationType::Generalization, &c1, &c2);
    QCOMPARE(c1.findSuperClassConcepts(UMLClassifier::ALL).size(), 0);
    c1.addAssociationEnd(&a1);
    QCOMPARE(c1.findSuperClassConcepts(UMLClassifier::ALL).size(), 1);
    UMLAssociation a2(Uml::AssociationType::Realization, &c1, &c2);
    c1.addAssociationEnd(&a2);
    QCOMPARE(c1.findSuperClassConcepts(UMLClassifier::ALL).size(), 2);
}

void TEST_classifier::test_findSubClassConcepts()
{
    UMLClassifier c1("Test A");
    UMLClassifier c2("Test B");
    UMLAssociation a1(Uml::AssociationType::Generalization, &c1, &c2);
    QCOMPARE(c2.findSubClassConcepts(UMLClassifier::ALL).size(), 0);
    c2.addAssociationEnd(&a1);
    QCOMPARE(c2.findSubClassConcepts(UMLClassifier::ALL).size(), 1);
    UMLAssociation a2(Uml::AssociationType::Realization, &c1, &c2);
    c2.addAssociationEnd(&a2);
    QCOMPARE(c2.findSubClassConcepts(UMLClassifier::ALL).size(), 2);
}

void TEST_classifier::test_setGetClassAssoc()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_isInterface()
{
    UMLClassifier c1("Test A");
    QCOMPARE(c1.isInterface(), false);
    c1.setBaseType(UMLObject::ObjectType::ot_Interface);
    QCOMPARE(c1.isInterface(), true);
    c1.setBaseType(UMLObject::ObjectType::ot_Class);
    QCOMPARE(c1.isInterface(), false);
}

void TEST_classifier::test_setGetOriginType()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_setGetIsReference()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_hasAbstractOps()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_makeChildObject()
{
    IS_NOT_IMPL();
}

void TEST_classifier::test_getUniAssociationToBeImplemented()
{
    IS_NOT_IMPL();
}

typedef TestUML<UMLClassifier, const QString&> TestUMLClassifier;

void TEST_classifier::test_saveAndLoad()
{
    UMLPackage parent("test package");
    TestUMLClassifier c1("Test A");
    c1.setUMLPackage(&parent);
    UMLOperation o1(nullptr, "testop1");
    c1.addOperation(&o1);
    UMLOperation o2(nullptr, "testop2");
    c1.addOperation(&o2);
    QDomDocument save = c1.testSave1();
    //c1.testDump("save");
    TestUMLClassifier c2;
    c2.setUMLPackage(&parent);
    QCOMPARE(c2.testLoad1(save), true);
    //c2.testDump("after load");
    QCOMPARE(c2.testSave1().toString(), save.toString());
}

QTEST_MAIN(TEST_classifier)
