/*!
  Copyright (c) 2016 Jed Watson.
  Licensed under the MIT License (MIT), see
  http://jedwatson.github.io/classnames
*/
/* global define */

(function () {
    'use strict';

    var classNames = (function () {
        // don't inherit from Object so we can skip hasOwnProperty check later
        // http://stackoverflow.com/questions/15518328/creating-js-object-with-object-createnull#answer-21079232
        function StorageObject() {}
        StorageObject.prototype = Object.create(null);

        function _parseArray (resultSet, array) {
            var length = array.length;

            for (var i = 0; i < length; ++i) {
                _parse(resultSet, array[i]);
            }
        }

        var hasOwn = {}.hasOwnProperty;

        function _parseNumber (resultSet, num) {
            resultSet[num] = true;
        }

        function _parseObject (resultSet, object) {
            for (var k in object) {
                if (hasOwn.call(object, k)) {
                    // set value to false instead of deleting it to avoid changing object structure
                    // https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/#de-referencing-misconceptions
                    resultSet[k] = !!object[k];
                }
            }
        }

        var SPACE = /\s+/;
        function _parseString (resultSet, str) {
            var array = str.split(SPACE);
            var length = array.length;

            for (var i = 0; i < length; ++i) {
                resultSet[array[i]] = true;
            }
        }

        function _parse (resultSet, arg) {
            if (!arg) return;
            var argType = typeof arg;

            // 'foo bar'
            if (argType === 'string') {
                _parseString(resultSet, arg);

            // ['foo', 'bar', ...]
            } else if (Array.isArray(arg)) {
                _parseArray(resultSet, arg);

            // { 'foo': true, ... }
            } else if (argType === 'object') {
                _parseObject(resultSet, arg);

            // '130'
            } else if (argType === 'number') {
                _parseNumber(resultSet, arg);
            }
        }

        function _classNames () {
            // don't leak arguments
            // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
            var len = arguments.length;
            var args = Array(len);
            for (var i = 0; i < len; i++) {
                args[i] = arguments[i];
            }

            var classSet = new StorageObject();
            _parseArray(classSet, args);

            var list = [];

            for (var k in classSet) {
                if (classSet[k]) {
                    list.push(k)
                }
            }

            return list.join(' ');
        }

        return _classNames;
    })();

    if (typeof module !== 'undefined' && module.exports) {
        module.exports = classNames;
    } else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
        // register as 'classnames', consistent with npm package name
        define('classnames', [], function () {
            return classNames;
        });
    } else {
        window.classNames = classNames;
    }
}());
