/*-------------------------------------------------------------------------------
  esave.ado: extended save; wrapper for saving in different dataset formats

    Copyright (C) 2012  Daniel Bela (daniel.bela@lifbi.de)

    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 3 of the License, 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.  If not, see <http://www.gnu.org/licenses/>.

-------------------------------------------------------------------------------*/
*! esave.ado: extended save; wrapper for saving in different dataset formats
*! Daniel Bela (daniel.bela@lifbi.de), Leibniz Institute for Educational Trajectories (LIfBi), Germany
*! version 0.9 01 March 2012 - initial release
program define esave, nclass

	//preparing macros
	syntax anything(everything equalok) , [FORmat(string) Orphans EMPTYok ALL REName VALlabfile(passthru) ///
		DELIMiter(passthru) NONames NOQuote NOLabel SHeet(passthru) CELL(passthru) SHEETMODify SHEETREPlace ///
		FIRSTrow(passthru) DATEstring(passthru) MISSing(passthru) LOCALE(passthru) LEGible REPLACE VERBOSE]
	quietly: extractfilename `=trim(regexr(`"`anything'"',"^using ?",""))'
	local ext `r(extension)'
	local filename `r(filename)'
	local path `r(path)'
	if "`format'"=="ooxml" | "`format'"=="excel" | inlist(`"`ext'"',"xlsx","xls") version 12
	else version 10
	local noformatgiven 0
	if `"`format'"'=="" local noformatgiven 1

	// concatenate using dataset name - cleansed for (compound) double quotes, "using " prefix and trimmed
	if `"`path'"'!="" & `"`ext'"'!="" local using `path'`c(dirsep)'`filename'.`ext'
	else if `"`path'"'!="" local using `path'`c(dirsep)'`filename'
	else if `"`ext'"'!="" local using `filename'.`ext'

	// guess format from file extension options
	if `noformatgiven'==1 {
		if `"`ext'"'=="dta" local format "stata"
		else if `"`ext'"'=="dat" local format "ascii_tab"
		else if `"`ext'"'=="txt" local format "ascii_comma"
		else if `"`ext'"'=="csv" local format "ascii_comma"
		else if `"`ext'"'=="xpt" local format "sas"
		else if `"`ext'"'=="xml" local format "xml_excel"
		else if `"`ext'"'=="xlsx" local format "ooxml"
		else if `"`ext'"'=="xls" local format "excel"
	}

	// check for inconsistencies in options
	* format should be nonmissing by now
	if `"`format'"'=="" {
		noisily: display as error in smcl `"{bf:Warning:} file {opt format} for {it:`using'} not specified and not guessable from file extension. Assuming {it:stata} format."'
		local format stata
	}
	else if "`verbose'"=="verbose" & `noformatgiven'==1 noisily: display as text in smcl `"{bf:Info:} assuming {bf:`format'} format from file extension {it:`ext'}."'
	* don't mix up excel and ooxml format!
	if `"`format'"'=="excel" & regexm(`"`using'"',`"^.+\.xlsx$"') {
		local format "ooxml"
		noisily: display as error in smcl `"{bf:Warning:} file {it:format excel} does not match file extension of {it:`using'}. Changed to {it:ooxml} format."'
	}
	else if `"`format'"'=="ooxml" & regexm(`"`using'"',`"^.+\.xls$"') {
		local format "excel"
		noisily: display as error in smcl `"{bf:Warning:} file {it:format ooxml} does not match file extension of {it:`using'}. Changed to {it:excel} format."'
	}
	* use stata options only when applicable
	foreach opt in orphans emptyok {
		if "``opt''"!="" & "`format'"!="stata" noisily: display as error in smcl "{bf:Warning:} option {opt `opt'} is only applicable for {it:stata} format; ignored. Refer to {help euse:help file} for details."
	}
	* use stata and stata_old options only when applicable
	if "`all'"!="" & !inlist("`format'","stata","stata_old") noisily: display as error in smcl "{bf:Warning:} option {opt all} is only applicable for {it:stata} and {it:stata_old} formats; ignored. Refer to {help euse:help file} for details."
	* use ascii_custom option only when applicable
	if "`delimiter'"!="" & `"`format'"'!="ascii_custom" noisily: display as error in smcl "{bf:Warning:} option {opt delimiter} is only applicable for {it:ascii_custom} format; ignored. Refer to {help euse:help file} for details."
	* don't let -delimiter- be empty in ascii_custom format!
	if `"`format'"'=="ascii_custom" & "`delimiter'"=="" {
		noisily: display as error in smcl "{bf:Warning:} option {opt delimiter} is mandatory for format {it:ascii_custom}. Changed format to {it:ascii_tab}."
		local format "ascii_tab"
	}
	* use ascii options only when applicable
		foreach opt in names noquote {
		if "``opt''"!="" & !inlist("`format'","ascii_custom","ascii_tab","ascii_comma","ascii_semicolon") noisily: display as error in smcl "{bf:Warning:} option {opt `opt'} is only applicable for {it:ascii_comma}, {it:ascii_tab}, {it:ascii_semicolon} and {it:ascii_custom} formats; ignored. Refer to {help euse:help file} for details."
	}
	* use -nolabel- option only if applicable
	if "`nolabel'"!="" & !inlist("`format'","ooxml","excel","stata","stata_old","ascii_custom","ascii_tab","ascii_comma","ascii_semicolon") noisily: display as error in smcl "{bf:Warning:} option {opt nolabel} is only applicable for {it:stata}, {it:stata_old}, {it:ascii_comma}, {it:ascii_tab}, {it:ascii_semicolon} and {it:ascii_custom} formats; ignored. Refer to {help euse:help file} for details."
	* use sas options only if applicable
	foreach opt in rename vallabfile {
		if "``opt''"!="" & "`format'"!="sas" noisily: display as error in smcl "{bf:Warning:} option {opt `opt'} is only applicable for {it:sas} format; ignored. Refer to {help euse:help file} for details."
	}
	* use excel and ooxml options only if applicable
	foreach opt in sheet cell sheetmodify sheetreplace firstrow datestring missing locale {
		if "``opt''"!="" & !inlist("`format'","ooxml","excel") noisily: display as error in smcl "{bf:Warning:} option {opt `opt'} is only applicable for {it:ooxml} and {it:excel} formats; ignored. Refer to {help euse:help file} for details."
	}
	* use xml options only if applicable
	foreach opt in dtd legible {
		if "``opt''"!="" & !inlist("`format'","xml_stata","xml_excel") noisily: display as error in smcl "{bf:Warning:} option {opt `opt'} is only applicable for {it:xml_stata} and {it:xml_excel} formats; ignored. Refer to {help euse:help file} for details."
	}

	// use target file as indicated
	if `"`format'"'=="stata" quietly: save `"`using'"', `orphans' `emptyok' `all' `nolabel' `replace'
	else if `"`format'"'=="stata_old" quietly: saveold `"`using'"', `all' `nolabel' `replace'
	else if `"`format'"'=="ascii_tab" quietly: outsheet using `"`using'"', `nonames' `noquote' `nolabel' `replace'
	else if `"`format'"'=="ascii_comma" quietly: outsheet using `"`using'"', comma `nonames' `noquote' `nolabel' `replace'
	else if `"`format'"'=="ascii_semicolon" quietly: outsheet using `"`using'"', delimiter(";") `nonames' `noquote' `nolabel' `replace'
	else if `"`format'"'=="ascii_custom" quietly: outsheet using `"`using'"', `delimiter' `nonames' `noquote' `nolabel' `replace'
	else if `"`format'"'=="sas" {
		if c(version)>=12 quietly: export sasxport `"`using'"', `rename' `vallabfile' `replace'
		else quietly: fdasave `"`using'"', `rename' `vallabfile' `replace'
	}
	else if `"`format'"'=="xml_stata" quietly: xmlsave `"`using'"', doctype(dta) `dtd' `legible' `replace'
	else if `"`format'"'=="xml_excel" quietly: xmlsave `"`using'"', doctype(excel) `dtd' `legible' `replace'
	else if inlist(`"`format'"',"ooxml","excel") quietly: export excel using `"`using'"', `sheet' `cell' `sheetmodify' `sheetreplace' `firstrow' `datestring' `missing' `nolabel' `locale' `replace'
	else {
		noisily: display as error `"{bf:Warning:} you specified the {opt format} {bf:`format'}, but it is not supported. Refer to {help euse:help file} for supported formats."'
		exit 198
	}
	exit 0
end
//EOF