/*
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
ace.define('ace/mode/html_completions', ['require', 'exports', 'module' , 'ace/token_iterator'], function(require, exports, module) {


var TokenIterator = require("../token_iterator").TokenIterator;

var commonAttributes = [
    "accesskey",
    "class",
    "contenteditable",
    "contextmenu",
    "dir",
    "draggable",
    "dropzone",
    "hidden",
    "id",
    "lang",
    "spellcheck",
    "style",
    "tabindex",
    "title",
    "translate"
];

var eventAttributes = [
    "onabort",
    "onblur",
    "oncancel",
    "oncanplay",
    "oncanplaythrough",
    "onchange",
    "onclick",
    "onclose",
    "oncontextmenu",
    "oncuechange",
    "ondblclick",
    "ondrag",
    "ondragend",
    "ondragenter",
    "ondragleave",
    "ondragover",
    "ondragstart",
    "ondrop",
    "ondurationchange",
    "onemptied",
    "onended",
    "onerror",
    "onfocus",
    "oninput",
    "oninvalid",
    "onkeydown",
    "onkeypress",
    "onkeyup",
    "onload",
    "onloadeddata",
    "onloadedmetadata",
    "onloadstart",
    "onmousedown",
    "onmousemove",
    "onmouseout",
    "onmouseover",
    "onmouseup",
    "onmousewheel",
    "onpause",
    "onplay",
    "onplaying",
    "onprogress",
    "onratechange",
    "onreset",
    "onscroll",
    "onseeked",
    "onseeking",
    "onselect",
    "onshow",
    "onstalled",
    "onsubmit",
    "onsuspend",
    "ontimeupdate",
    "onvolumechange",
    "onwaiting"
];

var globalAttributes = commonAttributes.concat(eventAttributes);

var attributeMap = {
    "html": ["manifest"],
    "head": [],
    "title": [],
    "base": ["href", "target"],
    "link": ["href", "hreflang", "rel", "media", "type", "sizes"],
    "meta": ["http-equiv", "name", "content", "charset"],
    "style": ["type", "media", "scoped"],
    "script": ["charset", "type", "src", "defer", "async"],
    "noscript": ["href"],
    "body": ["onafterprint", "onbeforeprint", "onbeforeunload", "onhashchange", "onmessage", "onoffline", "onpopstate", "onredo", "onresize", "onstorage", "onundo", "onunload"],
    "section": [],
    "nav": [],
    "article": ["pubdate"],
    "aside": [],
    "h1": [],
    "h2": [],
    "h3": [],
    "h4": [],
    "h5": [],
    "h6": [],
    "header": [],
    "footer": [],
    "address": [],
    "main": [],
    "p": [],
    "hr": [],
    "pre": [],
    "blockquote": ["cite"],
    "ol": ["start", "reversed"],
    "ul": [],
    "li": ["value"],
    "dl": [],
    "dt": [],
    "dd": [],
    "figure": [],
    "figcaption": [],
    "div": [],
    "a": ["href", "target", "ping", "rel", "media", "hreflang", "type"],
    "em": [],
    "strong": [],
    "small": [],
    "s": [],
    "cite": [],
    "q": ["cite"],
    "dfn": [],
    "abbr": [],
    "data": [],
    "time": ["datetime"],
    "code": [],
    "var": [],
    "samp": [],
    "kbd": [],
    "sub": [],
    "sup": [],
    "i": [],
    "b": [],
    "u": [],
    "mark": [],
    "ruby": [],
    "rt": [],
    "rp": [],
    "bdi": [],
    "bdo": [],
    "span": [],
    "br": [],
    "wbr": [],
    "ins": ["cite", "datetime"],
    "del": ["cite", "datetime"],
    "img": ["alt", "src", "height", "width", "usemap", "ismap"],
    "iframe": ["name", "src", "height", "width", "sandbox", "seamless"],
    "embed": ["src", "height", "width", "type"],
    "object": ["param", "data", "type", "height" , "width", "usemap", "name", "form", "classid"],
    "param": ["name", "value"],
    "video": ["src", "autobuffer", "autoplay", "loop", "controls", "width", "height", "poster"],
    "audio": ["src", "autobuffer", "autoplay", "loop", "controls"],
    "source": ["src", "type", "media"],
    "track": ["kind", "src", "srclang", "label", "default"],
    "canvas": ["width", "height"],
    "map": ["name"],
    "area": ["shape", "coords", "href", "hreflang", "alt", "target", "media", "rel", "ping", "type"],
    "svg": [],
    "math": [],
    "table": ["summary"],
    "caption": [],
    "colgroup": ["span"],
    "col": ["span"],
    "tbody": [],
    "thead": [],
    "tfoot": [],
    "tr": [],
    "td": ["headers", "rowspan", "colspan"],
    "th": ["headers", "rowspan", "colspan", "scope"],
    "form": ["accept-charset", "action", "autocomplete", "enctype", "method", "name", "novalidate", "target"],
    "fieldset": ["disabled", "form", "name"],
    "legend": [],
    "label": ["form", "for"],
    "input": ["type", "accept", "alt", "autocomplete", "checked", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "height", "list", "max", "maxlength", "min", "multiple", "pattern", "placeholder", "readonly", "required", "size", "src", "step", "width", "files", "value"],
    "button": ["autofocus", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "name", "value", "type"],
    "select": ["autofocus", "disabled", "form", "multiple", "name", "size"],
    "datalist": [],
    "optgroup": ["disabled", "label"],
    "option": ["disabled", "selected", "label", "value"],
    "textarea": ["autofocus", "disabled", "form", "maxlength", "name", "placeholder", "readonly", "required", "rows", "cols", "wrap"],
    "keygen": ["autofocus", "challenge", "disabled", "form", "keytype", "name"],
    "output": ["for", "form", "name"],
    "progress": ["value", "max"],
    "meter": ["value", "min", "max", "low", "high", "optimum"],
    "details": ["open"],
    "summary": [],
    "command": ["type", "label", "icon", "disabled", "checked", "radiogroup", "command"],
    "menu": ["type", "label"],
    "dialog": ["open"]
};

var allElements = Object.keys(attributeMap);

function hasType(token, type) {
    var tokenTypes = token.type.split('.');
    return type.split('.').every(function(type){
        return (tokenTypes.indexOf(type) !== -1);
    });
}

function findTagName(session, pos) {
    var iterator = new TokenIterator(session, pos.row, pos.column);
    var token = iterator.getCurrentToken();
    if (!token || !hasType(token, 'tag') && !(hasType(token, 'text') && token.value.match('/'))){
        do {
            token = iterator.stepBackward();
        } while (token && (hasType(token, 'string') || hasType(token, 'operator') || hasType(token, 'attribute-name') || hasType(token, 'text')));
    }
    if (token && hasType(token, 'tag-name') && !iterator.stepBackward().value.match('/'))
        return token.value;
}

var HtmlCompletions = function() {

};

(function() {

    this.getCompletions = function(state, session, pos, prefix) {
        var token = session.getTokenAt(pos.row, pos.column);

        if (!token)
            return [];
        if (hasType(token, "tag-name") || (token.value == '<' && hasType(token, "text")))
            return this.getTagCompletions(state, session, pos, prefix);
        if (hasType(token, 'text') || hasType(token, 'attribute-name'))
            return this.getAttributeCompetions(state, session, pos, prefix);

        return [];
    };

    this.getTagCompletions = function(state, session, pos, prefix) {
        var elements = allElements;
        if (prefix) {
            elements = elements.filter(function(element){
                return element.indexOf(prefix) === 0;
            });
        }
        return elements.map(function(element){
            return {
                value: element,
                meta: "tag"
            };
        });
    };

    this.getAttributeCompetions = function(state, session, pos, prefix) {
        var tagName = findTagName(session, pos);
        if (!tagName)
            return [];
        var attributes = globalAttributes;
        if (tagName in attributeMap) {
            attributes = attributes.concat(attributeMap[tagName]);
        }
        if (prefix) {
            attributes = attributes.filter(function(attribute){
                return attribute.indexOf(prefix) === 0;
            });
        }
        return attributes.map(function(attribute){
            return {
                caption: attribute,
                snippet: attribute + '="$0"',
                meta: "attribute"
            };
        });
    };

}).call(HtmlCompletions.prototype);

exports.HtmlCompletions = HtmlCompletions;
});
