<cfimport prefix="c" taglib="."/>
<cfif thisTag.executionMode IS "end">
	<!--- <cfloop collection=#CALLER# item="item">
		<cfset structInsert(variables, item, CALLER[item], false)/>
	</cfloop> --->
	
	<cfparam name="ATTRIBUTES.query" type="query"/>
	<cfparam name="ATTRIBUTES.recordsPerPage" type="integer" default="500"/>
	<cfparam name="ATTRIBUTES.nStart" type="integer" default="1"/>
	<cfparam name="ATTRIBUTES.titleMap" type="struct" default=srtuctNew()/><!---for definition see: field_set.cfm--->
	<cfparam name="ATTRIBUTES.sortArray" type="array" default=arrayNew(1)/>	
	
	<cfset tableAttributeList="query,recordsPerPage,nStart,titleMap,sortArray"/>
	<cfset colAttributeList="lang,th,td,content,field,formatter,sortable,visible,columnOrder"/>
	<cfset tdAttributeList="content,field"/>
	
	
	<cfparam name="thisTag.columns" type="array"/>
	
	
	<cffunction name=reorderColumns output="No">
		<!--- Вариант сортировки. Вынимаем все элементы с указанным порядком в отдельную коллекцию, 
		после чего вставляем их в оставшуюся коллекцию на указанные позиции. 
		нет смысла делать вид, что мы реализуем что-то универсальное 
		(поле для сортировки в совершенно конкретном поле структуры в массиве), 
		поэтому ничего не передаем в аргументах, спокойно ссылаемся на окружение--->
		<cfset var tmpOrderedIndexes=ArrayNew(1)/>
		<cfset var tmpUnorderedIndexes=ArrayNew(1)/>
		
		<cfloop from=1 to=#arrayLen(thisTag.columns)# index="i">	
			<cfif thisTag.columns[i].columnOrder GT 0>
				<cfset arrayAppend(tmpOrderedIndexes,i)/>
			<cfelse>
				<cfset arrayAppend(tmpUnorderedIndexes,i)/>
			</cfif>
		</cfloop> 
		
		<cfloop from=#arrayLen(tmpOrderedIndexes)# to=1 step=-1 index="i">
		<!--- counting up-down preserves entry order for equal columnOrders  --->
			<cfset var pos=max(min(thisTag.columns[tmpOrderedIndexes[i]].columnOrder, len(tmpUnorderedIndexes)+1),1)/>
			<cfset arrayInsertAt(tmpUnorderedIndexes,pos,tmpOrderedIndexes[i])/>
		</cfloop> 
		
		<cfset var sortedColumns=ArrayNew(1)/>
		<cfloop from=1 to=#arrayLen(tmpUnorderedIndexes)# index="i">	
			<cfset sortedColumns[i]=thisTag.columns[tmpUnorderedIndexes[i]]/>
		</cfloop>
		
		<cfreturn sortedColumns/>
	</cffunction>
	
	<cfset sortedColumns=reorderColumns()/>
	
	<cfset thisTag.generatedContent=""/>

	<table<!--- passthrough additional attributes 
	---><cfoutput><cfloop collection=#ATTRIBUTES# item="attr"><!---
		---><cfif NOT listFindNoCase(tableAttributeList,attr)<!--- AND isSimpleValue(structFind(ATTRIBUTES,attr))--->> #attr#="#structFind(ATTRIBUTES,attr)#"</cfif><!---
	---></cfloop></cfoutput>>
	<thead>
		<tr>
		<cfloop array=#sortedColumns# index="column">
			<cfset th=column.th[1]/>			
			<th<!--- атрибуты колонки передаются в TH, хотя это выглядит не очень нужным --->
				<cfloop collection=#column# item="colAttr">
					<cfif NOT listFindNoCase(colAttributeList,colAttr)><cfoutput>#colAttr#="#structFind(column,colAttr)#" </cfoutput></cfif>
				</cfloop>>		
				<cfif len(column.field) AND column.sortable>
					<c:order_arrows sortArray=#ATTRIBUTES.sortArray# n=#ATTRIBUTES.titleMap[column.field].ordinal#<!--- attributeCollection=#extraAttributes#--->/>
				</cfif>
				<cfif len(th.content)>
					<cfset Evaluate("WriteOutput('#th.content#')")/>
				<cfelseif len(column.field)>
					<cfif structKeyExists(ATTRIBUTES.titleMap[column.field],"title")>
						<cfoutput>#ATTRIBUTES.titleMap[column.field].title#</cfoutput>
					</cfif>
				</cfif>
			</th>
		</cfloop>
		</tr>
	</thead>

	<tbody>
		<cfoutput query=#ATTRIBUTES.query# maxrows=#ATTRIBUTES.recordsPerPage# startrow=#ATTRIBUTES.nStart#>
		<tr>
		<cfloop array=#sortedColumns# index="column">
			<cfset td=column.td[1]/>
			<td<!--- Если нужно передать атрибут в TD, можно ввести тег <C:TD class="r"/> только как плейсхолдер для атрибутов, а поле будет получено от колонки --->
			<cfloop collection=#td# item="tdAttr">
				<cfif NOT listFindNoCase(tdAttributeList,tdAttr)>#tdAttr#="#structFind(td,tdAttr)#" </cfif>
			</cfloop>
			><cfif len(td.content)><cfset Evaluate("WriteOutput('#td.content#')")/><!---#td.content#--->
			<cfelseif len(td.field)>#ATTRIBUTES.query[td.field][currentRow]#
			<cfelseif len(column.field)>#column.formatter(ATTRIBUTES.query[column.field][currentRow])#
			</cfif></td>
		</cfloop>
		</tr>
		</cfoutput>
	</tbody>

	</table>
	<!--- <cfdump var=#variables#/> --->
</cfif>
<!--- <cfexit method="exitTag"/> --->

<cfscript>
/**
* Sorts an array of structures based on a key in the structures.
*
* @param aofS      Array of structures.
* @param key      Key to sort by.
* @param sortOrder      Order to sort by, asc or desc.
* @param sortType      Text, textnocase, or numeric.
* @param delim      Delimiter used for temporary data storage. Must not exist in data. Defaults to a period.
* @return Returns a sorted array.
* @author Nathan Dintenfass (nathan@changemedia.com)
* @version 1, December 10, 2001
*/
function arrayOfStructsSort(aOfS,key){
        //by default we'll use an ascending sort
        var sortOrder = "asc";        
        //by default, we'll use a textnocase sort
        var sortType = "textnocase";
        //by default, use ascii character 30 as the delim
        var delim = ".";
        //make an array to hold the sort stuff
        var sortArray = arraynew(1);
        //make an array to return
        var returnArray = arraynew(1);
        //grab the number of elements in the array (used in the loops)
        var count = arrayLen(aOfS);
        //make a variable to use in the loop
        var ii = 1;
        //if there is a 3rd argument, set the sortOrder
        if(arraylen(arguments) GT 2)
            sortOrder = arguments[3];
        //if there is a 4th argument, set the sortType
        if(arraylen(arguments) GT 3)
            sortType = arguments[4];
        //if there is a 5th argument, set the delim
        if(arraylen(arguments) GT 4)
            delim = arguments[5];
        //loop over the array of structs, building the sortArray
        for(ii = 1; ii lte count; ii = ii + 1)
            sortArray[ii] = aOfS[ii][key] & delim & ii;
        //now sort the array
        arraySort(sortArray,sortType,sortOrder);
        //now build the return array
        for(ii = 1; ii lte count; ii = ii + 1)
            returnArray[ii] = aOfS[listLast(sortArray[ii],delim)];
        //return the array
        return returnArray;
}
</cfscript>