// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/Basic.h>
#include <OB/Template.h>
#include <OB/TemplateI.h>

// ----------------------------------------------------------------------
// Template instantiations
// ----------------------------------------------------------------------

#ifndef HAVE_NO_EXPLICIT_TEMPLATES
template class OBFixSeq< CORBA_Short >;
template class OBSeqVar< OBFixSeq< CORBA_Short > >;

template class OBFixSeq< CORBA_Long >;
template class OBSeqVar< OBFixSeq< CORBA_Long > >;

template class OBFixSeq< CORBA_UShort >;
template class OBSeqVar< OBFixSeq< CORBA_UShort > >;

template class OBFixSeq< CORBA_ULong >;
template class OBSeqVar< OBFixSeq< CORBA_ULong > >;

template class OBFixSeq< CORBA_Float >;
template class OBSeqVar< OBFixSeq< CORBA_Float > >;

template class OBFixSeq< CORBA_Double >;
template class OBSeqVar< OBFixSeq< CORBA_Double > >;

template class OBFixSeq< OBUnsignedChar >;
template class OBSeqVar< OBFixSeq< OBUnsignedChar > >;

template class OBVarSeq< OBFixSeq< OBUnsignedChar > >;
template class OBSeqVar< OBVarSeq< OBFixSeq< OBUnsignedChar > > >;
#else
#ifdef HAVE_PRAGMA_DEFINE
#pragma define(OBFixSeq< CORBA_Short >)
#pragma define(OBSeqVar< OBFixSeq< CORBA_Short > >)

#pragma define(OBFixSeq< CORBA_Long >)
#pragma define(OBSeqVar< OBFixSeq< CORBA_Long > >)

#pragma define(OBFixSeq< CORBA_UShort >)
#pragma define(OBSeqVar< OBFixSeq< CORBA_UShort > >)

#pragma define(OBFixSeq< CORBA_ULong >)
#pragma define(OBSeqVar< OBFixSeq< CORBA_ULong > >)

#pragma define(OBFixSeq< CORBA_Float >)
#pragma define(OBSeqVar< OBFixSeq< CORBA_Float > >)

#pragma define(OBFixSeq< CORBA_Double >)
#pragma define(OBSeqVar< OBFixSeq< CORBA_Double > >)

#pragma define(OBFixSeq< OBUnsignedChar >)
#pragma define(OBSeqVar< OBFixSeq< OBUnsignedChar > >)

#pragma define(OBVarSeq< OBFixSeq< OBUnsignedChar > >)
#pragma define(OBSeqVar< OBVarSeq< OBFixSeq< OBUnsignedChar > > >)
#endif
#endif

// ----------------------------------------------------------------------
// Unbounded string sequence member implementation
// ----------------------------------------------------------------------

char**
OBStrSeq::allocbuf(CORBA_ULong n)
{
    char** p = (char**) OBAlloc(sizeof(char*), n);
    
    for(CORBA_ULong i = 0 ; i < n ; i++)
	p[i] = 0;

    return p;
}

void
OBStrSeq::freebuf(char** p)
{
    if(p)
    {
	CORBA_ULong n = OBAllocated(p);
	
	for(CORBA_ULong i = 0 ; i < n ; i++)
	    CORBA_string_free(p[i]);

	OBFree(p);
    }
}

OBStrSeq::OBStrSeq()
    : max_(0), len_(0), off_(0), rel_(true), data_(0)
{
}

OBStrSeq::OBStrSeq(CORBA_ULong m)
    : max_(m), len_(0), off_(0), rel_(true)
{
    if(max_ > 0)
	data_ = allocbuf(off_ + max_);
    else
	data_ = 0;

}

OBStrSeq::OBStrSeq(CORBA_ULong m, CORBA_ULong l, char** d, CORBA_Boolean r)
    : max_(m), len_(l), off_(0), rel_(r)
{
    assert_nca(len_ <= max_, OBNCASeqLenGrMax);
    data_ = d;
}

OBStrSeq::OBStrSeq(const OBStrSeq& r)
    : max_(0), len_(0), off_(0), rel_(true), data_(0)
{
    *this = r;
}

OBStrSeq&
OBStrSeq::operator=(const OBStrSeq& r)
{
    if(this != &r)
    {
	if(rel_)
	    freebuf(data_);
	
	max_ = r.max_;
	off_ = r.off_;
	len_ = r.len_;
	rel_ = true;

	if(max_ + off_ > 0)
	    data_ = allocbuf(off_ + max_);
	else
	    data_ = 0;

	for(CORBA_ULong i = 0 ; i < len_ ; i++)
	    data_[i + off_] = CORBA_string_dup(r.data_[i + off_]);
    }

    return *this;
}

void
OBStrSeq::length(CORBA_ULong newLen)
{
    if(newLen < len_ && rel_)
    {
	for(CORBA_ULong i = newLen ; i < len_ ; i++)
	{
	    CORBA_string_free(data_[i + off_]);
	    data_[i + off_] = 0;
	}
    }
    else if(max_ < newLen)
    {
	if(rel_ && off_ / 2 >= newLen - max_)
	{
	    CORBA_ULong diff = off_ / 2;
	    off_ -= diff;
	    max_ += diff;

	    CORBA_ULong i;

	    for(i = 0 ; i < len_ ; i++)
		data_[i + off_] = data_[i + off_ + diff];

	    for(i = 0 ; i < diff ; i++)
		data_[i + off_ + len_] = 0;
	}
	else
	{
	    char** old = data_;
	    
	    max_ = newLen > max_ * 2 ? newLen : max_ * 2;
	    data_ = allocbuf(off_ + max_);
	    
	    for(CORBA_ULong i = 0 ; i < len_ ; i++)
	    {
		if(rel_)
		{
		    data_[i + off_] = old[i + off_];
		    old[i + off_] = 0;
		}
		else
		    data_[i + off_] = CORBA_string_dup(old[i + off_]);
	    }
	    
	    if(rel_)
		freebuf(old);
	    
	    rel_ = true;
	}
    }
    
    len_ = newLen;
}

void
OBStrSeq::insert(char* p)
{
    if(off_ == 0)
    {
	if(rel_ && (max_ - len_) / 2 >= 1)
	{
	    CORBA_ULong diff = (max_ - len_) / 2;
	    off_ += diff;
	    max_ -= diff;

	    CORBA_ULong i;

	    for(i = len_ ; i > 0 ; i++)
 		data_[i - 1 + off_] = data_[i - 1 + off_ - diff];

	    for(i = 0 ; i < diff ; i++)
		data_[i + off_ - diff] = 0;
	}
	else
	{
	    char** old = data_;
	    CORBA_ULong offOld = off_;
	    
	    off_ = max_ > 1 ? max_ : 1;
	    data_ = allocbuf(off_ + max_);
	    
	    for(CORBA_ULong i = 0 ; i < len_ ; i++)
	    {
		if(rel_)
		{
		    data_[i + off_] = old[i + offOld];
		    old[i + offOld] = 0;
		}
		else
		    data_[i + off_] = CORBA_string_dup(old[i + offOld]);
	    }
	    
	    if(rel_)
		freebuf(old);
	    
	    rel_ = true;
	}
    }

    off_--;
    len_++;
    max_++;

    data_[0 + off_] = p;
}

void
OBStrSeq::append(char* p)
{
    length(len_ + 1);
    data_[len_ - 1 + off_] = p;
}

void
OBStrSeq::remove(CORBA_ULong n)
{
    assert_nca(n < len_, OBNCASeqRange);

    if(!rel_)
    {
	char** old = data_;
	data_ = allocbuf(off_ + max_);
	    
	for(CORBA_ULong i = 0 ; i < len_ ; i++)
	{
	    data_[i + off_] = old[i + off_];
	    old[i + off_] = 0;
	}

	freebuf(old);
	    
	rel_ = true;
    }

    CORBA_string_free(data_[n + off_]);
    
    if(n >= len_ / 2)
    {
	for(CORBA_ULong i = n ; i < len_ - 1 ; i++)
	    data_[i + off_] = data_[i + 1 + off_];
	
	data_[len_ - 1 + off_] = 0;
	
	len_--;
    }
    else
    {
	for(CORBA_ULong i = n ; i > 0 ; i--)
	    data_[i + off_] = data_[i - 1 + off_];
	
	data_[0 + off_] = 0;
	
	off_++;
	len_--;
	max_--;
    }
}

void
OBStrSeq::consume(OBStrSeq& r)
{
    max_ = r.max_;
    off_ = r.off_;
    len_ = r.len_;
    rel_ = r.rel_;
    data_ = r.data_;

    r.max_ = 0;
    r.len_ = 0;
    r.off_ = 0;
    r.rel_ = true;
    r.data_ = 0;
}

//
// Unbounded string sequence _var type
//
#ifndef HAVE_NO_EXPLICIT_TEMPLATES
template class OBSeqVar< OBStrSeq >;
#endif

// ----------------------------------------------------------------------
// CDR for basic sequence types
// ----------------------------------------------------------------------

void
OBMarshal(const OBFixSeq< OBUnsignedChar >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< OBUnsignedChar >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< OBUnsignedChar >& seq, const CORBA_Octet*& oct,
	    bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBVarSeq< OBFixSeq< OBUnsignedChar > >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    for(CORBA_ULong i = 0 ; i < seq.length() ; i++)
        OBMarshal(seq[i], oct);
}

void
OBMarshalCount(const OBVarSeq< OBFixSeq< OBUnsignedChar > >& seq,
	       CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    for(CORBA_ULong i = 0 ; i < seq.length() ; i++)
        OBMarshalCount(seq[i], count);
}

void
OBUnmarshal(OBVarSeq< OBFixSeq< OBUnsignedChar > >& seq,
	    const CORBA_Octet*& coct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, coct, swap);
    seq.length(len);
    for(CORBA_ULong i = 0 ; i < len ; i++)
        OBUnmarshal(seq[i], coct, swap);
}

void
OBMarshal(const OBFixSeq< CORBA_Short >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< CORBA_Short >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< CORBA_Short >& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBFixSeq< CORBA_UShort >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< CORBA_UShort >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< CORBA_UShort >& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBFixSeq< CORBA_Long >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< CORBA_Long >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< CORBA_Long >& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBFixSeq< CORBA_ULong >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< CORBA_ULong >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< CORBA_ULong >& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBFixSeq< CORBA_Float >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< CORBA_Float >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< CORBA_Float >& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBFixSeq< CORBA_Double >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    OBMarshalMulti(seq.data(), oct, seq.length());
}

void
OBMarshalCount(const OBFixSeq< CORBA_Double >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    OBMarshalCountMulti(seq.data(), count, seq.length());
}

void
OBUnmarshal(OBFixSeq< CORBA_Double >& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    OBUnmarshalMulti(seq.data(), oct, swap, len);
}

void
OBMarshal(const OBStrSeq& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    for(CORBA_ULong i = 0 ; i < seq.length() ; i++)
	OBMarshal(seq[i], oct);
}

void
OBMarshalCount(const OBStrSeq& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    for(CORBA_ULong i = 0 ; i < seq.length() ; i++)
	OBMarshalCount(seq[i], count);

}

void
OBUnmarshal(OBStrSeq& seq, const CORBA_Octet*& oct, bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    for(CORBA_ULong i = 0 ; i < len ; i++)
	OBUnmarshal(seq[i].inout(), oct, swap);
}
