(function(PCG){
    var svgNS = 'http://www.w3.org/2000/svg';

// I am too lazy to do DOM manually / anyway this solution is optimal enough

    var setters = {
        cls: function(el) {
            return function(cls) {
                if( el.tagName.toLowerCase() === 'svg' ){
                    el.setAttribute( 'class', cls );
                }else{
                    el.className = cls;
                }
            }
        },
        attr: function(el, attrName) {
            return function(val) {
              if(val !== void 0 && val !== false){
                el.setAttribute( attrName, val );
              }else{
                el.removeAttribute(attrName)
              }
            }
        }
    };

// ~jsx h function
    var domEl = function( type, cfg ){
        cfg = cfg || {};
        var cls = cfg.cls,
            style = cfg.style,
            attr = cfg.attr,
            prop = cfg.prop,
            on = cfg.on,
            renderTo = cfg.renderTo,
            el = cfg.el || document.createElement( type ),
            classList = el.classList;

        var i, _i;

        if( cls ){
            if(typeof cls === 'function'){
                cls(setters.cls(el));
            }else{
                if( el.tagName.toLowerCase() === 'svg' ){
                    el.setAttribute( 'class', cls );
                }else{
                    el.className = cls;
                }
            }
            //if(el.className !== cls)debugger
            //cls.split( ' ' ).forEach( function( clsItem ){ classList.add( clsItem ); });
        }

        if( style ){
            PCG.apply( el.style, style );
        }

        for( i in attr ){
            if(attr.hasOwnProperty( i )){
                if( typeof attr[ i ] === 'function' ){
                    attr[ i ]( setters.attr( el, i ) );
                }else{
                    setters.attr( el, i )( attr[ i ] );
                }
            }
        }

        for( i in prop ){
            prop.hasOwnProperty( i ) && ( el[ i ] = prop[ i ] );
        }

        for( i in on ){
            on.hasOwnProperty( i ) && el.addEventListener( i, on[ i ] );
        }

        for( i = 2, _i = arguments.length; i < _i; i++ ){
            var child = arguments[ i ];
            D.appendChild( el, child );
        }

        if( renderTo ){
            D.appendChild( renderTo, el );
        }

        return el;
    };

    var D = PCG.D = {
        svg: null,
        label: null,
        div: null,
        span: null,
        path: null,
        canvas: null,
        input: null,
        textarea: null,
        tBody: null,
        tHead: null,
        th: null,
        td: null,
        tr: null,
        Text: function( val ){ return document.createTextNode( val );}
    };
    'div,span,input,label,canvas,span,textarea,table,tr,td,th,tBody,tHead'.split( ',' ).forEach( function( name ){
        D[ name ] = function(){
            return domEl.apply( null, [ name ].concat([].slice.call(arguments)))
        };
    } );

    'svg,path,circle'.split( ',' ).forEach( function( name ){
        D[ name ] = function( cfg){
            if( !cfg ){
                cfg = {};
            }
            cfg.el = document.createElementNS( svgNS, name );
            cfg.el.setAttribute( 'xmlns', svgNS );
            return domEl.apply( null, [ null ].concat([].slice.call(arguments)))
        };
    } );

    D.html = function(cfg){
      var el = domEl('div', cfg);
      el.innerHTML =  [].slice.call(arguments,1).join('\n');
      return el;
    };

    D.removeChildren = function(el){
        var subEl;
        while((subEl = el.lastChild)){
            el.removeChild(subEl);
        }
    };

    D.appendChild = function(el, subEl){
        var type = typeof subEl;

        if(subEl === null){
            return ;
        }
        if( type !== 'object' ){
            if( type === 'function' ){
                var tmp = D.span( {} );
                el.appendChild( tmp );
                subEl( function(){
                    D.removeChildren( tmp );
                    D.appendChild( tmp, [].slice.call( arguments ) )
                } )
            }else if( subEl !== void 0 && subEl !== false && subEl !== null ){
                el.appendChild( D.Text( subEl ) );
            }
        }else if('dom' in subEl){
            el.appendChild( subEl.dom );
        }else if( Array.isArray(subEl) ){
            subEl.forEach(subEl => D.appendChild( el, subEl ) );
        }else{
            el.appendChild( subEl );
        }
    };
    D.join = function(arr, delimiter){
        var out = [], isFn = typeof delimiter === 'function';

        for( var i = 0, _i = arr.length - 1; i < _i; i++ ){
            out.push(arr[i], isFn?delimiter(i):delimiter);
        }
        if(i < _i+1)
            out.push(arr[i]);
        return out;
    };

    D.cls = function() {
        var out = [], i = 0, _i = arguments.length, token, tmp, key;
        for(;i<_i;i++){
            token = arguments[i];
            if(typeof token === 'string'&& token){
                out.push( token );
            }else if(typeof token === 'object'){
                if(Array.isArray(token)){
                    tmp = D.cls.apply(null, token);
                    tmp && out.push( token );
                }else{
                    for(key in token){
                        token[key] && out.push( key );
                    }
                }
            }else if(typeof token === 'function'){

            }
        }
        return out.join(' ');
    };
    D.escapeCls = function(cls) {
        return (cls+'').replace(/[^a-zA-Z0-9\-_]/g,'');
    }
})(window['PCG']);