// --- class CSV ---

function classCsv(opt)
{
this.opt;
this.data;

this.escapeCsvValue = function(str,escape_always)
	{
	var reg, patt, repl, csv, csv_patt;
	csv  = this.opt.parse;
	patt = this.data.patt;
	str  = str + ''; //convert to string
	re   = new RegExp(patt.val_enc,'g');
	str  = str.replace(re,csv.esc + '$1');
	re   = new RegExp(patt.val_sep,'g');
	str  = escape_always==true || str.search(re)!=-1 ? csv.esc + str + csv.esc : str;
	// ignore RFC 4180
	return str;
	}

this.export = function(arrData,escape_always)
	{
	var i, row, csv, out;
	var escape_always = !isExist(escape_always) ? false : escape_always;
	csv = this.opt.parse;
	out = [];
	for (i=0; i<arrData.length; ++i)
		{
		row = arrData[i];
		for (j=0; j<row.length; ++j)
			{
			row[j] = this.escapeCsvValue(row[j],escape_always);
			}
		out[i] = row.join(csv.col);
		}
	return out.join(csv.row);
	}

this.import = function(strData,cb_escape)
	{
        var out, arrMatches, strMatchedDelimiter, strMatchedValue, re1, re2, bool;
	csv  = this.opt.parse;
	patt = this.data.patt;
	bool = isFunction(cb_escape);
        re1  = new RegExp(patt.imp2, "gi");
        out  = [[]];
        arrMatches = null;
        while (arrMatches = re1.exec( strData ))
		{
		strMatchedDelimiter = arrMatches[ 1 ];
		if (strMatchedDelimiter.length && strMatchedDelimiter !== csv.col)
			{
			out.push([]);
			}
		if (arrMatches[ 2 ])
			{
			re2 = new RegExp( patt.imp1, "g" );
			strMatchedValue = arrMatches[ 2 ].replace(re2, csv.enc);
			}
		else	{
			strMatchedValue = arrMatches[ 3 ];
			}
		strMatchedValue = typeof(strMatchedValue)!='undefined' ? strMatchedValue + '' : '';
		strMatchedValue = bool ? cb_escape(strMatchedValue) : strMatchedValue;
		out[out.length-1].push(strMatchedValue);
		}
	return out;
	}

this.init = function(opt)
	{
	var p = {};
	this.opt = {};
	this.opt.parse = {
		row : "\n",	// row separator
		col : ';',	// col separator
		enc : '"',	// enclosure string
		esc : '"'	// escape csv chars in string
		}
	this.data = {};
	this.data.patt = {};
	if (isExist(opt) && isObject(opt))
		{
		for (i in this.opt.parse)
			{
			this.opt.parse[i] = isSet(opt,i) && isString(opt[i]) ? opt[i] : this.opt.parse[i];
			}
		}
	for (i in this.opt.parse)
		{
		p[i] = escapeRegexp(this.opt.parse[i]);
		}
	p.val_enc = '([' + p.enc + '])';
	p.val_sep = '[' + p.col + p.row + ']';
	p.imp1 = p.esc + p.enc;
	p.imp2 = "(" + p.col + "|\\r?" + p.row + "|\\r|^)" +		// Delimiters
		 "(?:" + p.enc + "([^" + p.enc + "]*(?:" + p.imp1 + "[^" + p.enc + "]*)*)" + p.enc + "|" +	// Quoted fields
		 "([^"+ p.enc + p.col + "\\r" + p.row + "]*))"		// Standard fields
	this.data.patt = p;
	}

this.init(opt);

}

CSV = new classCsv();
