function Chat() {    
    _self = this;
    var timeout = null;

    var _input = null;
    var _send_btn = null;
    var _user_list = null;
    var _close_btn = null;
    var _smiles_box = null;
    var _rooms_block = null;
    var _room_messages = null;
    var _newwnd_btn = null;

    var _last_msg_id = 0;
        
    var rooms = new Array();
    var _active_room_id = 0;

    var max_messages = 100;

    this.init = function (send_btn, input_area, close_btn, rooms_block, user_list, room_messages, smile_box, newwnd_btn) {
        _input = $(input_area);
        _send_btn = $(send_btn);
        
        if (newwnd_btn && newwnd_btn != '') {
            _newwnd_btn = $(newwnd_btn);
            _newwnd_btn.bind('click', _self.openAtNewWindow);

            _close_btn = $(close_btn);
        } else {
            _last_msg_id = Chat.getSingleWndAttr();
        }

        _user_list = $(user_list);
        _rooms_block = $(rooms_block);
        _room_messages = $(room_messages);


        _smiles_box = $(smile_box);
        this.renderSmilesBox();

        _room_messages.css('display', 'none');
        this.getRoomList();
        this.getOnlineUsers();

        _send_btn.bind('click', _self.sendMessageClick);

        if (_close_btn != null ) {
            _close_btn.bind('click', _self.close);
        }
    }

    this.errorHandler = function(XMLHttpRequest, textStatus, errorThrown) {
        timeout = setTimeout('_self.getMessages();', 4000);
    }

    this.scrollDown = function (id) {
        var parent = rooms[id].el.parent();
        if (parent[0]) {
            parent.scrollTop(parent[0].scrollHeight)
        }
    }

    this.changeActiveRoom = function (room_id) {
        if (!(room_id && rooms[room_id]) || _active_room_id == room_id)
            return;
        if ( _active_room_id > 0) {
            // Прячем окно сообщений комнаты
            rooms[_active_room_id].el.css('display', 'none');
            _rooms_block.children('[room_id='+_active_room_id+']').css('color', '#c0c0c0');
        }
        _active_room_id = room_id;
        // Показывам окно сообщений комнаты
        rooms[room_id].el.css('display', 'block');
        _rooms_block.children('[room_id='+_active_room_id+']').css('color', '#0f4057');
        _input.focus();
        this.scrollDown(room_id);
    }

    this.getRoomList = function () {
        $.ajax({
            url: '/index.php/chat/getRooms?_=' + Chat.getRandomStr(),
            type: 'POST',
            cache: false,
            dataType: 'json',
            error: this.errorHandler,
            success: function (data, textStatus) {
                // clear container
                _rooms_block.html('');
                var el = null;
                rooms = [];
                var el_count = Chat.objectSize(data);
                
                for (var room_id in data) {                    
                    if (data[room_id] == null) {
                        el_count--;
                        continue;
                    }
                    el = document.createElement('a');
                    el.href = '#';
                    el.room_id = room_id;
                    el.innerHTML = data[room_id];                    
                    el.onclick = function(){                        
                        _self.changeActiveRoom(this.room_id);
                        return false;
                    }
                    _rooms_block.append(el);
                    if ( el_count-- > 0 )
                        _rooms_block.append(' / ');
                    //                    
                    rooms[room_id] = new Object;
                    rooms[room_id].el = _room_messages.clone();                    
                    _room_messages.parent().append(rooms[room_id].el);
                    if (_active_room_id == 0) {                        
                        _self.changeActiveRoom(room_id);
                    }
                }                
            }
        });
    }

    this.insertAtCaretPos = function(text) {
        var range = _input.caret();
        var value = _input.val();
        _input.val(value.substr(0, range.start) + text + value.substr(range.end, value.length));
        _input.caret((range.start ? range.start : 0) + text.length);
    }

    this.smileClick = function() {
        _self.insertAtCaretPos(this.smile);
    }

    this.renderSmilesBox = function () {
        var li = null;
        _smiles_box.html('');
        var img = new Array();
        for (var s in Chat.smiles) {            
            if ($.inArray(Chat.smiles[s], img) != -1)
                continue;
            li = document.createElement('li');
            li.onclick = _self.smileClick;
            li.smile = s;
            li.innerHTML = '<img src="/i/chat/smiles/'+Chat.smiles[s]+'" alt="'+s+'" title="'+s+'"/>';
            _smiles_box.append(li);
            img.push(Chat.smiles[s]);
        }
        img = [];
    }

    this.updateUserList = function ( user_id, user_name, remove ) {
        var el = _user_list.children('[user_id='+user_id+']')[0];
        var rc = false;

        if (remove) {
            if (el != null) {
                $(el).remove();
                rc = true;
            }
        } else {
            if ( el == null ) {
                el = document.createElement('li');

                $(el).addClass('zebra');

                el.user_id = user_id;
                var usr_a = document.createElement('a');
                usr_a.innerHTML = user_name;
                usr_a.onclick = _self.usernameClick;
                $(el).append(usr_a);
                _user_list.append(el);
                rc = true;
            }
        }
        return rc;
    }

    this.getUserName = function(user_id) {
        return _user_list.children('[user_id='+user_id+']').children('a').html();
    }

    this.getOnlineUsers = function () {
        $.ajax({
            url: '/index.php/chat/getOnlineUsers?_=' + Chat.getRandomStr(),
            cache: false,
            type: 'POST',            
            dataType: 'json',
            error: this.errorHandler,
            success: function (data, textStatus) {
                _user_list.html('');
                for (var user_id in data) {
                    _self.updateUserList(user_id, data[user_id], false)
                }
                _self.getMessages();
            }
        });
    }

    this.sendMessageClick = function () {
        var text = _input.val();
        _input.val('');
        _self.sendMessage(text);

    }

    this.checkForOpenChat = function () {
        return (rooms.length > 0);
    }

    this.sendMessage = function (text) {
        if (text == '')
            return;

        clearTimeout(timeout);
        $.ajax({
            url: '/index.php/chat/postMessage?_=' + Chat.getRandomStr(),
            type: 'POST',
            cache: false,
            dataType: 'json',
            data: {
                msg: text,
                room: _active_room_id,
                last_id: _last_msg_id
            },
            error: function(XMLHttpRequest, textStatus, errorThrown){                
                //_self.sendMessage(text);
            },
            success: function (data, textStatus) {
                _self.renderMessages(data);
                clearTimeout(timeout);
                timeout = setTimeout('_self.getMessages();', 2000);
            }
        });        
    }

    this.usernameClick = function(){
        _self.insertAtCaretPos(this.innerHTML + ': ');
    }

    this.formatMessage = function (msg) {
        var res = $(document.createElement('li'));
        res.attr('message_id', msg.id);
        res.attr('message_type', msg.type);
        res.append('[ ' + msg.time + ' ');

        var user_name = null;
        if ( msg.type == 2 || msg.type == 3 ){
            if (!_self.updateUserList(msg.user, msg.msg, (msg.type == 3))) {
                res.remove();
                return null;
            }
            if (msg.type == 2) {
                msg.msg = 'Пользователь вошел';
            } else {
                user_name = msg.msg;
                msg.msg = 'Пользователь вышел';
            }
        }

        var usr_a = document.createElement('a');
        usr_a.innerHTML = user_name ? user_name : _self.getUserName(msg.user);
        usr_a.onclick = _self.usernameClick;
        res.append(usr_a);
        res.append(' ] '+ Chat.parseSmiles(msg.msg));

        return res;
    }



    this.addRoomMessage = function (id, msg) {
        if ( !rooms[id] )
            return;

        if (id != _active_room_id) {
            if(msg.attr('message_type') != 2 && msg.attr('message_type')!=3){
                _rooms_block.children('[room_id='+id+']').css('color', '#a0bd18');
            }
        }

        if (!rooms[id].el.children(':last').hasClass('zebra')){
            msg.addClass('zebra');
        }

        var li = rooms[id].el.children('li');
        for( i = li.size() - max_messages; i>=0 ; i--){
            $(li[i]).remove();
        }

        rooms[id].el.append(msg);
        this.scrollDown(id);

    }

    this.renderMessages = function (room_msg) {        
        for (var msg in room_msg) {
            if ( _last_msg_id >= room_msg[msg].id )
                continue;

            _last_msg_id = room_msg[msg].id;

            var obj = _self.formatMessage(room_msg[msg]);
            if (!obj) 
                continue;

            if ( room_msg[msg].room == 0 ) {
                for ( var r in rooms ) {
                    if (rooms[r] != null)
                        _self.addRoomMessage(r, obj.clone(true));
                }
                obj.remove();
            } else {                                
                _self.addRoomMessage(room_msg[msg].room, obj);
            }
        }
    }

    this.getMessages = function () {
        clearTimeout(timeout);
        if (!_self.checkForOpenChat())
            return;
        $.ajax({
            url: '/index.php/chat/getMessages?_=' + Chat.getRandomStr(),
            type: 'POST',            
            dataType: 'json',
            error: this.errorHandler,
            data: {last_id: _last_msg_id},
            success: function (data, textStatus) {                
                _self.renderMessages(data);
                timeout = setTimeout('_self.getMessages();', 2000);
            }
        });
    }

    this.close = function() {        
        clearTimeout(timeout);
        _close_btn.unbind('click', _self.close);
        if (_newwnd_btn) {
            _newwnd_btn.unbind('click', _self.openAtNewWindow);
        }
        _send_btn.unbind('click', _self.sendMessage)
        for (var r in rooms) {
            if (rooms[r].el)
                rooms[r].el.remove();
        }
        rooms = [];
        _last_msg_id = 0;
        _room_messages.css('display', 'block');
    }

    this.openAtNewWindow = function() {
        // Получим Id первого отображаемого сообщени
        var min_id = _last_msg_id;
        for (var room_id in rooms) {
            var room_f_msg_id = rooms[room_id].el.children(':first').attr('message_id');
            if (min_id > room_f_msg_id) min_id = room_f_msg_id;
        }
        var wnd = window.open('/index.php/chat/singleWindow?' + min_id, 'Chat', "width=797,height=713,resizable=no,menubar=no,toolbar=no");
        
        _self.close();
        wnd.focus();
        return true;
    }

}

Chat.smiles = {
    "O:-)" : 'angel.png',
    ":-@" : 'angry.png',
    ":@" : 'angry.png',
    "/;o" : 'arrogant.png',
    "/am" : 'arrogant.png',
    "~x(" : 'at-wits-end.png',
    "/bye" : 'bye.png',
    ":-c" : 'call-me.png',
    "=D>" : 'clap.png',
    "<:o)" : 'party.png',
    ":O)" : 'clown.png',
    ":-ss" : 'nailbiting.png',
    ":-S" : 'confused.png',
    ":S" : 'confused.png',
    "<):)" : 'cowboy.png',
    "/:*" : 'desire.png',
    "/se" : 'desire.png',
    "(6)" : 'devil.png',
    "#-o" : 'doh.png',
    "=P~" : 'drool.png',
    ":-[" : 'embarrassed.png',
    "8-)" : 'glasses-cool.png',
    "8-|" : 'glasses-nerdy.png',
    "/go" : 'go-away.png',
    "/;@" : 'hypnotized.png',
    "/love" : 'in-love.png',
    "/aiq" : 'in-love.png',
    ":-*" : 'kiss.png',
    "/mm" : 'lashes.png',
    "/&" : 'lashes.png',
    "*JOKINGLY*" : 'laugh.png',
    "l-)" : 'loser.png',
    "(u)" : 'love-over.png',
    ":^o" : 'lying.png',
    ">:p" : 'mad-tongue.png',
    ":->" : 'mean.png',
    ":>" : 'mean.png',
    ":-|" : 'neutral.png',
    ":|" : 'neutral.png',
    ":)]" : 'on-the-phone.png',    
    "/?" : 'question.png',
    ":-#" : 'quiet.png',
    "=))" : 'rotfl.png',
    ":-j" : 'rotfl.png',
    ":-(" : 'sad.png',
    ":(" : 'sad.png',
    "^o)" : 'sarcastic.png',
    "=-o" : 'shock.png',
    "+o(" : 'sick.png',
    "/:Q" : 'silly.png',
    "/:Z" : 'sleepy.png',
    ":-d" : 'smile-big.png',
    ":d" : 'smile-big.png',
    ":-)" : 'smile.png',
    ":)" : 'smile.png',
    "/:L" : 'sweat.png',
    ":-/" : 'thinking.png',
    ":-t" : 'time-out.png',
    ":P" : 'tongue.png',
    ":-P" : 'tongue.png',
    ":-w" : 'waiting.png',
    "/:'(" : 'weep.png',
    ":'(" : 'crying.png',
    ";-)" : 'wink.png',
    ";)" : 'wink.png',
    "|-)" : 'yawn.png'
};

Chat.parseSmiles = function (str) {
    for (smile in Chat.smiles) {
        str = str.replace(smile.replace('>','&gt;','g').replace('<','&lt;','g'), '<img src="/i/chat/smiles/' + Chat.smiles[smile] + '" alt=""/>', 'gi')
    }
    return str;
}

Chat.objectSize = function(obj){
  var len = obj.length ? --obj.length : -1;
    for (var k in obj)
      len++;
  return len;
};

Chat.getRandomStr = function () {    
    return new Date().getTime().toString().substr(8);
}

Chat.getSingleWndAttr = function () {
    var attr_arr = /singleWindow\?(\d+)[#]?$/.exec(document.location);
    return (attr_arr) ? parseInt(attr_arr[1]) : 0;
}

function CreateChat(flag) {
    var new_wnd = null;
    if (!flag) {
        Overlay.show();        
        $('div#chat').slideDown('slow');
        new_wnd = '#chat_newwnd_btn';
    }
    c = new Chat();
    c.init(
        '#chat_send_btn',
        '#chat_msg_field',
        '#chat_close_btn',
        '#chat_rooms_place',
        '#chat_users_control',
        '#chat_room_messages',
        '.smileArea',
        new_wnd
    );
}

function update_smiles_area( block ){
    if (!block) {
        return false;
    }

    var show = block.children(':last').css('display') == 'none';
    if (! show) {
        // Определим позицию по высоте первого дочернего элемента
        var top_offset = block.children(':first').position().top;
    }

    block.children().each(function() {
        var curr_j_obj = $(this);
        if (show) {
            if (curr_j_obj.css('display') == 'none') {
                curr_j_obj.css('display', 'block');
            }
        } else {
            var this_offset = curr_j_obj.position().top;
            if ( this_offset > top_offset ) {
                curr_j_obj.css('display', 'none');
            }
        }
    });
    return true;
}
