///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoViewObject.cc 
// ------------------
// Cego view object entry implementation
//     
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2010 Bjoern Lemke
//
// 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, 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; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: CegoViewObject
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

// base includes
#include <lfc/Tokenizer.h>

// cego includes
#include "CegoViewObject.h"
#include "CegoXMLHelper.h"
#include "CegoXMLdef.h"
#include "CegoTypeConverter.h"

#include <string.h>
#include <stdlib.h>

CegoViewObject::CegoViewObject()
{
    _subCOList.Insert(this);
}


CegoViewObject::CegoViewObject(Element *pVO)
{
    putElement(pVO);
    _subCOList.Insert(this);
}

CegoViewObject::CegoViewObject(const CegoViewObject& vo) : CegoContentObject(vo)
{
    _viewStmt = vo._viewStmt;
    _subCOList.Insert(this);
}

CegoViewObject::CegoViewObject(const Chain& viewName, int tabSetId) : CegoContentObject(tabSetId, CegoObject::VIEW, viewName)
{
    _subCOList.Insert(this);
}

CegoViewObject::CegoViewObject(int tabSetId, const Chain& viewName, const ListT<CegoField>& schema, const Chain& viewStmt) : CegoContentObject(tabSetId, CegoObject::VIEW, viewName, viewName, schema)
{
    _viewStmt = viewStmt;    
    _subCOList.Insert(this);
}

CegoViewObject::~CegoViewObject()
{   
}

void CegoViewObject::setSchema(const ListT<CegoField>& schema)
{
    _schema = schema;
}

int CegoViewObject::getEntrySize() const
{
    int entrySize = CegoContentObject::getBaseContentSize();
    entrySize += _viewStmt.length() + 1;
    return entrySize;
}

void CegoViewObject::encode(char *buf)
{
    char* bufPtr = buf;
    int entrySize = getEntrySize();
    CegoContentObject::encodeBaseContent(bufPtr, entrySize);
    bufPtr += CegoContentObject::getBaseContentSize();
    memcpy (bufPtr, (char*)_viewStmt , _viewStmt.length() + 1);
}

void CegoViewObject::decode(char *buf)
{
    char* bufPtr = buf;
    int size;
    CegoContentObject::decodeBaseContent(bufPtr, size);
    bufPtr += CegoContentObject::getBaseContentSize();
    _viewStmt = Chain(bufPtr);
}

void CegoViewObject::setViewStmt(const Chain& viewStmt)
{
    _viewStmt = viewStmt;
}

const Chain& CegoViewObject::getViewStmt() const
{
    return _viewStmt;
}

CegoViewObject& CegoViewObject::operator = ( const CegoViewObject& vo)
{
    CegoContentObject::operator=(vo);
    _viewStmt = vo._viewStmt;
    return (*this);
}

bool CegoViewObject::operator == ( const CegoViewObject& vo)
{
    return CegoContentObject::operator==(vo);
}

Chain CegoViewObject::toChain() const
{
    return getTabName() + Chain(" ") + getName();
}

Element* CegoViewObject::getElement() const
{
    Element* pRoot = new Element(XML_OBJ_ELEMENT);

    pRoot->setAttribute(XML_TSID_ATTR, Chain(getTabSetId()));
    pRoot->setAttribute(XML_OBJTYPE_ATTR, XML_VIEWOBJ_VALUE);	
    pRoot->setAttribute(XML_OBJNAME_ATTR, getName());

    CegoField *pF = _schema.First();
    while ( pF ) 
    {
	Element *pColElement = new Element(XML_SCHEMA_ELEMENT);


	CegoXMLHelper xh;
	xh.setColInfo(pColElement, pF);

	pRoot->addContent(pColElement);
	pF = _schema.Next();
    }

    pRoot->setAttribute(XML_VIEWSTMT_ATTR, _viewStmt);

    return pRoot;
}

void CegoViewObject::putElement(Element* pElement)
{

    Element *pRoot = pElement;
    
    if ( pRoot )
    {
	
	Chain objName = pRoot->getAttributeValue(XML_OBJNAME_ATTR); 
	int tabSetId = pRoot->getAttributeValue(XML_TSID_ATTR).asInteger();
	
	setName(objName);
	setTabName(objName);
	setTabSetId(tabSetId);

	setType(CegoObject::VIEW);
	
	ListT<Element*> colList = pRoot->getChildren(XML_SCHEMA_ELEMENT);
	
	ListT<CegoField> fl;
	Element **pCol = colList.First();
	while ( pCol ) 
	{
	    Chain colName = (*pCol)->getAttributeValue(XML_COLNAME_ATTR);
	    Chain colType = (*pCol)->getAttributeValue(XML_COLTYPE_ATTR);
	    Chain colSize = (*pCol)->getAttributeValue(XML_COLSIZE_ATTR);
	    Chain colNullable = (*pCol)->getAttributeValue(XML_COLNULLABLE_ATTR);
	    bool isNullable;
	    if ( colNullable == Chain(XML_TRUE_VALUE) ) 
		isNullable = true;
	    else
		isNullable = false;
	    
	    CegoFieldValue defValue;

	    CegoTypeConverter tc;
	    CegoDataType dataType = tc.getTypeId(colType);
	    
	    CegoField f(CegoField(objName, objName, colName, dataType, colSize.asInteger(), defValue, isNullable));		
	    fl.Insert(f);

	    pCol = colList.Next();
	}
	
	setSchema(fl);

	_viewStmt = pRoot->getAttributeValue(XML_VIEWSTMT_ATTR);
    }    
}

Chain CegoViewObject::getFormatted() const
{

    Chain s;
	
    int maxAttrLen = 12;
    CegoField* pF = _schema.First();
    while (pF)
    {
	if (maxAttrLen < pF->getAttrName().length())
	    maxAttrLen = pF->getAttrName().length();
	pF = _schema.Next();
    }

    int maxFillLen = maxAttrLen + 28;

    Tokenizer pvt(_viewStmt, "\n");
    
    Chain line;
    
    while ( pvt.nextToken(line) )
    {
	if ( line.length() > maxFillLen )
	    maxFillLen = line.length();
    }
    
    s += Chain("+") + fill("-", maxAttrLen) + fill(Chain("-"), 28) + Chain("+\n");
    s += "| ObjectName : ";
    s += getName();
    s += fill(" ", maxAttrLen + 15 - getName().length()) + Chain("|\n");
	
    s += Chain("| ObjectType : ");
    switch ( getType() )
    {
    case CegoObject::TABLE:
	s += Chain("table          "); 
	break;
    case CegoObject::INDEX:
	s += Chain("index          ");
	break;
    case CegoObject::UINDEX:
	s += Chain("unique index   ");
	break;
    case CegoObject::PINDEX:
	s += Chain("primary index  ");
	break;
    case CegoObject::VIEW:
	s += Chain("view           ");
	break;
    default:
	break;
    }
	
    s += fill(" ", maxAttrLen-1 ) + Chain("|\n");
	
    s += Chain("+-----------") + fill("-", maxAttrLen-10) + Chain("+---------------+----------+\n");
    s += Chain("| Attribute ") +  fill(" ", maxAttrLen-10) + Chain("| Type          | Nullable |\n");
    s += Chain("+-----------") + fill("-", maxAttrLen-10) + Chain("+---------------+----------+\n");
	
    pF = _schema.First();
    while (pF)
    {
	
	int num = maxAttrLen - pF->getAttrName().length() ;
	s += Chain("| ") + pF->getAttrName() + fill(" ", num) + Chain(" |");

	switch (pF->getType())
	{
	case INT_TYPE:
	{
	    s += Chain("  int          |");
	    break;
	}
	case LONG_TYPE:
	{
	    s += Chain("  long         |");
	    break;
	}
	case BOOL_TYPE:
	{
	    s += Chain("  bool         |");
	    break;
	}
	case DATETIME_TYPE:
	{
	    s += Chain("  datetime     |");
	    break;
	}
	case VARCHAR_TYPE:
	{
	    Chain l(pF->getLength());
	    s += Chain("  string[") + l + Chain("]") + fill(" ", 6 - l.length()) + Chain("|");
	    break;
	}
	case BIGINT_TYPE:
	{
	    Chain l(pF->getLength());
	    s += Chain("  bigint[") + l + Chain("]") + fill(" ", 6 - l.length()) + Chain("|");
	    break;
	}
	case SMALLINT_TYPE:
	{
	    s += Chain("  smallint     |");
	    break;
	}
	case TINYINT_TYPE:
	{
	    s += Chain("  tinyint      |");
	    break;
	}
	
	case DECIMAL_TYPE:
	{
	    Chain l(pF->getLength());
	    s += Chain("  decimal[") + l + Chain("]") + fill(" ", 5 - l.length()) + Chain("|");
	    break;
	}
	case FIXED_TYPE:
	{
	    Chain l(pF->getLength());
	    s += Chain("  fixed[") + l + Chain("]") + fill(" ", 7 - l.length()) + Chain("|");
	    break;
	}
	case FLOAT_TYPE:
	{
	    s += Chain(" float         |");
	    break;
	}
	case DOUBLE_TYPE:
	{
	    s += Chain(" double        |");
	    break;
	}
	case BLOB_TYPE:
	{
	    s += Chain(" blob          |");
	    break;
	}
	default:
	    break;
	}
	if ( pF->isNullable() )
	    s +=  Chain(" y        |");
	else
	    s += " n        |";
	
	pF = _schema.Next();
	    
	s += Chain("\n");
    }
    s += Chain("+") + fill("-", maxAttrLen + 1) + Chain("+---------------+----------+\n");

    Tokenizer vt(_viewStmt, "\n");
        
    while ( vt.nextToken(line) )
    {
	s += Chain("| ") + line + fill(" ", maxFillLen-line.length()) + Chain("|\n");
    }
    s += Chain("+") + fill("-", maxFillLen) + Chain("+\n");

    return s;

}

Chain CegoViewObject::fill(const Chain& s, int num) const
{
    
    Chain fs = Chain("");
    while (num > 0)
    {
	fs = fs + s;
	num--;
    }

    return fs;
}

CegoContentObject* CegoViewObject::clone(bool isAttrRef)
{
    CegoViewObject *pClone = new CegoViewObject(*this);
    pClone->setViewStmt(_viewStmt);
    return (pClone);
}
