// Basic types implementation for JavaX
// Require: prototype.js
// Bugs: Grep TODO's and NOTE's in the code


// Exception
var Exception = Class.create({
initialize: function(sMsg, iCode) {
	this.message=sMsg;
	this.code=iCode;
},
Serialize: function(oSerializer) {
	oSerializer.BeginType("Exception");
	oSerializer.SerializeString(this.message);
	if(this.code) oSerializer.SerializeInt(this.code);
	oSerializer.EndType("Exception");
},
Restore: function(oRestorer) {
	oRestorer.BeginType("Exception");
	this.message=oRestorer.RestoreString();
	if(oRestorer.GetType()=="u") {
		this.code=oRestorer.Restore().Value();
	}
	else this.code=undefined;
	oRestorer.EndType("Exception");
},
ErrorCode: function() {
	return this.code;
},
Message: function() {
	return this.message;
},
toString: function() {
	return this.message;
}});

// ------------------------------------------------------------
// 'Optional' container for optional data types
// for proper serialization of optional types
// ------------------------------------------------------------
function optional(oValue) { return new Optional(oValue); }

var Optional = Class.create({
initialize: function(oValue) {
	if (typeof(oValue) == "undefined") {
		this.bNone_ = true;
	} else {
		this.bNone_ = false;
		this.oValue_ = oValue;
	}
},
Value: function() {
	return this.oValue_;
},
IsNull: function() {
	return this.bNone_;
},
SetNull: function() {
	this.bNone_ = true;
},
Serialize: function(oSerializer) {
	if (this.bNone_) {
		oSerializer.BeginType("none");
		oSerializer.EndType("none");
	}
	else {
		oSerializer.BeginType("optional");
		oSerializer.Serialize(this.oValue_);
		oSerializer.EndType("optional");
	}
},
Restore: function(oRestorer) {
	var sTypeName = oRestorer.GetType();
	if (sTypeName == "none") {
		oRestorer.BeginType("none");
		oRestorer.EndType("none");
		this.bNone_ = true;
	}
	else {
		oRestorer.BeginType("optional");
		this.bNone_ = false;
		this.oValue_ = oRestorer.Restore();
		oRestorer.EndType("optional");
	}
},
toString: function() {
	if (this.IsNull()) return "<optional::none>";
	else if (typeof(this.oValue_.toString) == "function") return this.oValue_.toString();
	else return "<optional::object>";
}
});

// ------------------------------------------------------------
// int32_t type
// ------------------------------------------------------------
// Wrapper
function int(value) { return new Int(value); }

var Int = Class.create({
initialize: function(value) {
	this.value_ = parseInt(value);
},
Value: function() {
	return this.value_;
},
Serialize: function(oSerializer) {
	oSerializer.SerializeInt(this.value_);
},
Restore: function(oRestorer) {
	this.value_ = oRestorer.RestoreInt();
},
toString: function() {
	return this.value_.toString();
}
});

// ------------------------------------------------------------
// uint32_t type
// ------------------------------------------------------------
function unsigned(oValue) { return new Unsigned(oValue); }

var Unsigned = Class.create({
initialize: function(value) {
	this.value_ = parseInt(value);
},
Value: function() {
	return this.value_;
},
Serialize: function(oSerializer) {
	oSerializer.BeginType("u");
// TODO: Bad impl! not pure unsigned (31-bit)
	oSerializer.Serialize(new Int(this.value_));
	oSerializer.EndType("u");
},
Restore: function(oRestorer) {
	oRestorer.BeginType("u");
	this.value_ = oRestorer.Restore().Value();
	if(this.value_<0) {
		this.value_= this.value_+4294967296;
	}
	oRestorer.EndType("u");
},
toString: function() {
	return this.value_.toString();
}
});

// ------------------------------------------------------------
// int64_t type
// ------------------------------------------------------------
// Wrapper
function int64(value) { return new Int64(value); }

var Int64 = Class.create({
initialize: function(value) {
	// TODO: BAD (cannot constuct true Int64 from long number)
	this.value_ = parseInt(value);
},
Value: function() {
	return this.value_;
},
Serialize: function(oSerializer) {
	oSerializer.SerializeInt64(this.value_);
},
Restore: function(oRestorer) {
	this.value_ = oRestorer.RestoreInt64().Value();
},
toString: function() {
	return this.value_.toString();
}
});

// ------------------------------------------------------------
// uint64_t type
// ------------------------------------------------------------
var UInt64 = Class.create({
initialize: function(value) {
	// TODO: BAD (cannot constuct true Int64 from long number)
	// TODO: BAD: not pure-32bit
	this.value_ = parseInt(value);
},
Value: function() {
	return this.value_;
},
Serialize: function(oSerializer) {
	oSerializer.BeginType("ul");
	oSerializer.SerializeInt64(this.value_);
	oSerializer.EndType("ul");
},
Restore: function(oRestorer) {
	oRestorer.BeginType("ul");
	this.value_ = oRestorer.RestoreInt64().Value();
	oRestorer.EndType("ul");
},
toString: function() {
	return this.value_.toString();
}
});

// ------------------------------------------------------------
// double type
// ------------------------------------------------------------
// Wrapper
function double(value) { return new Double(value); }

var Double = Class.create({
initialize: function(value) {
	this.value_ = parseFloat(value);
},
Value: function() {
	return this.value_;
},
Serialize: function(oSerializer) {
	oSerializer.SerializeDouble(this.value_);
},
Restore: function(oRestorer) {
	this.value_ = oRestorer.RestoreDouble();
},
toString: function() {
	return this.value_.toString();
}
});

var Blob = Class.create({
initialize: function(value) {
	this.value=value;
},
Value: function() {
	return this.value;
},
Serialize: function(oSerializer) {
	oSerializer.SerializeBinary(this.value);
},
Restore: function(oRestorer) {
	this.value = oRestorer.RestoreBinary();
},
toString: function() {
	return this.value;
}
});

var BlobFile = Class.create({
	initialize: function(fileName, mimeType, fileBody){
		this.fileName = fileName;
		this.mimeType = mimeType;
		this.fileBody = new Blob(fileBody);
	},
	Serialize: function(oSerializer){
		oSerializer.BeginType("BlobFile");
		oSerializer.Serialize(this.fileName);
		oSerializer.Serialize(this.mimeType);
		oSerializer.Serialize(this.fileBody);
		oSerializer.EndType("BlobFile");
	},
	Restore: function(oRestorer){
		oRestorer.BeginType("BlobFile");
		this.fileName = oRestorer.Restore();
		this.mimeType = oRestorer.Restore();
		this.fileBody = oRestorer.Restore();
		oRestorer.EndType("BlobFile");
	}
});


// ------------------------------------------------------------
// BlobRef type
// ------------------------------------------------------------
var BlobRef = Class.create({
initialize: function(sBlobID) {
	this.sBlobID = sBlobID;
},
Value: function() {
	return this.sBlobID;
},
Serialize: function(oSerializer) {
	oSerializer.BeginType("BlobRef");
	oSerializer.SerializeString(this.sBlobID);
	oSerializer.EndType("BlobRef");
},
Restore: function(oRestorer) {
	oRestorer.BeginType("BlobRef");
	this.sBlobID=oRestorer.RestoreString();
	oRestorer.EndType("BlobRef");
},
toString: function() {
	if(this.sBlobID==undefined) return "";
	return this.sBlobID.toString();
}
});

// ------------------------------------------------------------
// Time type (boost::posix_time in iso string representation)
// ------------------------------------------------------------
var Time = Class.create({
	year: NaN,
	month: NaN,
	day: NaN,
	
	hh: NaN,
	mm: NaN,
	ss: NaN,

initialize: function(sTime) {
	if (typeof(sTime) == 'undefined' || !sTime) {
		this.setNull();
		return; // leave undefined
	}
	this.parseTime(sTime);
},
Value: function() {
	return this.toISOString();
},
Serialize: function(oSerializer) {
	oSerializer.BeginType("Time");
	oSerializer.Serialize(this.toISOString());
	oSerializer.EndType("Time");
},
Restore: function(oRestorer) {
	oRestorer.BeginType("Time");
	var sTime = oRestorer.Restore();
	oRestorer.EndType("Time");
	if (sTime == "not-a-date-time") this.setNull();
	else this.parseTime(sTime);
},
parseTime: function(sTime) {
	// to make this compatible with ATime and ADate
	this.year = parseInt(sTime.substr(0,4),10);
	this.month = parseInt(sTime.substr(4,2),10);
	this.day = parseInt(sTime.substr(6,2),10);
	this.hh = parseInt(sTime.substr(9,2),10);
	this.mm = parseInt(sTime.substr(11,2),10);
	this.ss = parseInt(sTime.substr(13,2),10);
	if (
		isNaN(this.year) ||
		isNaN(this.month) ||
		isNaN(this.day) ||
		isNaN(this.hh) ||
		isNaN(this.mm) ||
		isNaN(this.ss) ) {
		this.setNull();
		throw new Error("Invalid ISO format in Time: '"+sTime+"'. ");
	}
},
setNull: function() {
	this.year = NaN;
	this.month = NaN;
	this.day = NaN;
	
	this.hh = NaN;
	this.mm = NaN;
	this.ss = NaN;
},
toISOString: function() {
	if (isNaN(this.year)) return "not-a-date-time";
	return (
		this.year.toPaddedString(4)+
		this.month.toPaddedString(2)+
		this.day.toPaddedString(2)+
		'T'+
		this.hh.toPaddedString(2)+
		this.mm.toPaddedString(2)+
		this.ss.toPaddedString(2) );
},
toString: function() {
	if (isNaN(this.year)) return "null";
	
	var monthName=DateInput.of_monthname[this.month];
	return this.day.toPaddedString(2)+'-'+
			monthName+'-'+this.year.toPaddedString(4)+' '+
			this.hh.toPaddedString(2)+':'+
			this.mm.toPaddedString(2)+':'+
			this.ss.toPaddedString(2);
}
});

