
/**
* General use custom tags.
* Some are taken from http://www.grails.org/Contribute+a+Tag#checkBoxList
*/
class CustomTagLib {
    static namespace = 'custom'

    def resources = { attrs ->
        ///@todo: should include our javascript and do setup here.
    }

    /**
    * Checkbox list that can be used as a more user-friendly alternative to a multiselect list box.
     * Usage:
     * To map the selected ids to corresponding domain objects,
     * an additional set method is required in the containing domain class:
     *       //  This additional setter is used to convert the checkBoxList string or string array
     *       //  of ids selected to the corresponding domain objects.
     *       public void setAssetSubItemsFromCheckBoxList(ids) {
     *           def idList = []
     *           if(ids instanceof String) {
     *                   if(ids.isInteger())
     *                       idList << ids.toInteger()
     *           }
     *           else {
     *               ids.each() {
     *                   if(it.isInteger())
     *                       idList << it.toInteger()
     *               }
     *           }
     *           this.assetSubItems = idList.collect { AssetSubItem.get( it ) }
     *       }
     *
     * Then a line in the controller:
     *      assetInstance.setAssetSubItemsFromCheckBoxList(params.assetSubItems)
     *
     * Fields:
     *    name - the property name.
     *    from - the list to select from.
     *    value - the current value.
     *    optionKey - the key to use.
     *    sortBy - (optional) the attribute to sort the from list by.
     *    displayFields - (optional) defaults to the objects toString()
     *    displayFieldsSeparator - (optional) defaults to a space.
     *    linkController - (optional, requires linkAction.) the controller to use for a link to the objects in the checkBoxList.
     *    linkAction - (optional, requires linkController.) the action to use for a link to the objects in the checkBoxList.
     *
     * Example:
     *    <!--
     *    <custom:checkBoxList name="assetSubItems"
     *                                    from="${AssetSubItem.list()}"
     *                                    value="${assetInstance?.assetSubItems.collect{it.id}}"
     *                                    optionKey="id"
     *                                    sortBy="description"
     *                                    displayFields="['id', 'name']"
     *                                    displayFieldsSeparator=', '
     *                                    linkController="assetSubItemDetailed"
     *                                    linkAction="show"/>
     *    -->
     *
     */

    def checkBoxList = {attrs, body ->

        def from = attrs.from
        def value = attrs.value
        def cname = attrs.name
        def isChecked, ht, wd, style, html

        def sortBy = attrs.sortBy
        def displayFields = attrs.displayFields
        def displayFieldsSeparator = attrs.displayFieldsSeparator ?: ' '
        def linkController = attrs.linkController
        def linkAction = attrs.linkAction

        def displayValue = " "

        // sets the style to override height and/or width if either of them
        // is specified, else the default from the CSS is taken
        style = "style='"
        if(attrs.height)
            style += "height:${attrs.height};"
        if(attrs.width)
            style += "width:${attrs.width};"
        if(style.length() == "style='".length())
            style = ""
        else
            style += "'" // closing single quote

        html = "<ul class='CheckBoxList' " + style + ">"

        out << html

        if(sortBy)
            from.sort { p1, p2 -> p1[sortBy].compareToIgnoreCase(p2[sortBy]) }

        from.each { obj ->

            displayValue = " "

            if(linkController && linkAction)
                   displayValue += "<a href=\"${createLink(controller: linkController, action: linkAction, id: obj.id).encodeAsHTML()}\">"

            if(displayFields) {
                displayValue += displayFields.collect { obj[it] }.join(displayFieldsSeparator)
            }
            else displayValue += obj // use the obj's default toString()

            if(linkController && linkAction)
                displayValue += "</a>"

            // if we wanted to select the checkbox using a click anywhere on the label (also hover effect)
            // but grails does not recognize index suffix in the name as an array:
            // cname = "${attrs.name}[${idx++}]"
            // and put this inside the li: <label for='$cname'>...</label>

            isChecked = (value?.contains(obj."${attrs.optionKey}"))? true: false

            out << "<li>" << checkBox(name:cname, value:obj."${attrs.optionKey}", checked: isChecked) << displayValue << "</li>"
        }

        out << "</ul>"

    } // checkBoxList

    def sortableColumnWithImg = { attrs, body ->
        def writer = out
        if(!attrs.property)
            throwTagError("Tag [sortableColumn] is missing required attribute [property]")

//         if(!attrs.title && !attrs.titleKey)
//             throwTagError("Tag [sortableColumn] is missing required attribute [title] or [titleKey]")

        def property = attrs.remove("property")
        def action = attrs.action ? attrs.remove("action") : (actionName ?: "list")

        def defaultOrder = attrs.remove("defaultOrder")
        if(defaultOrder != "desc") defaultOrder = "asc"

        // current sorting property and order
        def sort = params.sort
        def order = params.order

        // add sorting property and params to link params
        def linkParams = [:]
        if(params.id) linkParams.put("id",params.id)
        if(attrs.params) linkParams.putAll(attrs.remove("params"))
        linkParams.sort = property

        // determine and add sorting order for this column to link params
        attrs.class = (attrs.class ? "${attrs.class} sortable" : "sortable")
        if(property == sort) {
            attrs.class = attrs.class + " sorted " + order
            if(order == "asc")
                linkParams.order = "desc"
            else
                linkParams.order = "asc"
        }
        else
            linkParams.order = defaultOrder

        // determine column title
//         def title = attrs.remove("title")
//         def titleKey = attrs.remove("titleKey")
//         if(titleKey) {
//             if(!title) title = titleKey
//             def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
//             def locale = RCU.getLocale(request)
// 
//             title = messageSource.getMessage(titleKey, null, title, locale)
//         }

        // Image.
        def imgSrc = attrs.remove("imgSrc")
        def imgAlt = attrs.remove("imgAlt")
        def img = "<img src=${imgSrc} alt=${imgAlt} />"

        writer << "<th "

        // process remaining attributes
        attrs.each { k, v ->
            writer << "${k}=\"${v.encodeAsHTML()}\" "
        }
        writer << ">${link(action:action, params:linkParams) { img } }"
//         writer << body()
        writer << "</th>"
    }

} // end class