class WsChatController < WsController

    def start_polling_messages
        connection_store[:clients].each do |client|
            client.add_message_callback do |message|
                #noinspection RubyAssignmentExpressionInConditionalInspection

                if message.body
                    process_incoming_message(message)
                elsif request = message.first_element('sync_contacts_request')
                    # toto mozem prijat len ako admin multichatu
                    send_contacts(message, request.attribute('chat_id').to_s)
                elsif answer = message.first_element('synced_contacts')
                    # toto mozem prijat len ako ucastnik multichatu (nie admin)
                    sync_contacts_frontend(message, answer.attribute('chat_id').to_s)
                elsif answer = message.first_element('exported_chat')
                    import_people_in_chat(message, answer.attribute('chat_id').to_s)
                elsif message.attribute('destroy_multichat')
                    destroy_multichat(message, message.attribute('chat_id').to_s)
                elsif message.attribute('req_update_contacts')
                    update_attendants_in_multichat(message, message.attribute('chat_id').to_s)
                end
                #TODO: upozornit na pisanie spravy
                #TODO: odoslat informaciu o tom, ze pisem spravu
                #else
                #    send_message 'app.chat.messageState',
                #                 state: message.chat_state,
                #                 from: message.from.strip.to_s,
                #                 to: message.to.strip.to_s,
                #                 message: message.body,
                #                 chat_id: if message.attribute(:is_simulating) then message.attribute(:chat_id) end
            end
        end
    end

    def import_people_in_chat(message, chat_id)
        #Rails.logger.debug ['imported chat arrived', message.to_s, chat_id]

        client = find_client(message.to.strip.to_s)
        contacts = xml_contacts_to_array(message.first_element('exported_chat'))

        connection_store[:opened_chats] = {} if ! connection_store[:opened_chats]
        connection_store[:opened_chats][client] = {} if ! connection_store[:opened_chats][client]
        connection_store[:opened_chats][client][chat_id] = {attendants: contacts, owner: message.from.node + '@' + message.from.domain}

        #Rails.logger.debug [
        #    owner: message.from.node + '@' + message.from.domain,
        #    chat_id:  chat_id,
        #    contacts: contacts
        #]

        send_message 'app.chat.importChat',
                     owner:    message.from.node + '@' + message.from.domain,
                     chat_id:  chat_id,
                     contacts: contacts
    end

    # Owner vytvori najprv u seba novy multichat
    def new_multichat
        me = message[:chatOwner]
        hash = Digest::SHA2.hexdigest(me)
        id = hash + Time.now.to_f.to_s
        client = find_client(me)

        connection_store[:opened_chats] = {} if ! connection_store[:opened_chats]
        connection_store[:opened_chats][client] = {} if ! connection_store[:opened_chats][client]
        connection_store[:opened_chats][client][id] = {attendants: [], owner: me}

        trigger_success id: id
    end

    # Owner posle novemu cloveku informaciu o chat_id a kontaktoch
    def add_to_multichat
        client = find_client(message[:chatOwner])

        chat_id  = message[:chatId]
        somebody = message[:jid]

        connection_store[:opened_chats][client][chat_id][:attendants] << somebody

        contacts = connection_store[:opened_chats][client][chat_id][:attendants]
        client.send(MessageBuilder::export_multichat(client.jid.strip.to_s, somebody, chat_id, contacts))

        trigger_success
    end

    def send_chat_message
        me = message[:from]
        client = find_client(me)

        if client
            chat_id = message[:chatId]
            if chat_id
                attendants = connection_store[:opened_chats][client][chat_id][:attendants] + [connection_store[:opened_chats][client][chat_id][:owner]]
                attendants -= [client.jid.strip.to_s]

                messages = MessageBuilder::build_multi_messages(message[:message], client.jid.strip.to_s, attendants, chat_id)
            else
                messages = [MessageBuilder::build_message(message[:message], client.jid.strip.to_s, message[:to])]
            end

            # Xmpp4r doesn't support XEP-0033 (multicast messages)
            messages.each do |message|
                #Rails.logger.debug message.to_s
                client.send(message)
            end

            trigger_success message[:message]
        else
            trigger_failure
        end
    end

    def sync_chat_contacts
        client = find_client(message[:me])
        chat_id = message[:chatId]

        owner = connection_store[:opened_chats][client][chat_id][:owner]
        client.send(MessageBuilder::ask_for_multichat_contacts(client.jid.strip.to_s, owner, chat_id))
    end

    def i_closed_multichat
        chat_id = message[:chatId]
        client  = find_client(message[:me])
        me      = client.jid.strip.to_s
        owner   = connection_store[:opened_chats][client][chat_id][:owner]

        if owner == me
            attendants = connection_store[:opened_chats][client][chat_id][:attendants]
            attendants.each do |attendant|
                client.send(MessageBuilder::destroy_multichat(me, attendant, chat_id))
            end
        else
            changes = {removed: [me]}
            client.send(MessageBuilder::req_update_multichat_contacts(me, owner, chat_id, changes))
        end
    end

    def kick_from_multichat
        chat_id = message[:chatId]
        client  = find_client(message[:me])
        me      = client.jid.strip.to_s
        kick    = message[:kick]

        contacts = connection_store[:opened_chats][client][chat_id][:attendants]
        contacts -= [kick]

        connection_store[:opened_chats][client][chat_id][:attendants] = contacts

        client.send(MessageBuilder::destroy_multichat(me, kick, chat_id))

        if contacts.empty?
            connection_store[:opened_chats][client].delete(chat_id)
            send_message 'app.chat.destroyMultichat', chat_id: chat_id
        else
            contacts.each do |contact|
                client.send(MessageBuilder::send_multichat_contacts(client.jid.strip.to_s, contact, chat_id, contacts))
            end
        end
    end

    private

    def process_incoming_message(message)
        #Rails.logger.debug message
        send_message 'app.chat.messageReceived',
                     from: message.from.strip.to_s,
                     to: message.to.strip.to_s,
                     message: message.body,
                     chat_id: message.attribute('chat_id').to_s
    end

    def send_contacts(message, chat_id)
        from = message.from.strip.to_s
        client = find_client(message.to.strip.to_s)
        contacts = connection_store[:opened_chats][client][chat_id][:attendants]
        client.send(MessageBuilder::send_multichat_contacts(client.jid.strip.to_s, from, chat_id, contacts))
    end

    def sync_contacts_frontend(message, chat_id)
        contacts = xml_contacts_to_array(message.first_element('sync_contacts'))

        send_message 'app.chat.updateSyncedContacts',
                     me: message.to.strip.to_s,
                     contacts: contacts,
                     chat_id: chat_id
    end

    def xml_contacts_to_array(xml_contacts)
        xml_contacts.get_elements('contact').map do |contact|
            contact.text
        end
    end

    def destroy_multichat(message, chat_id)
        client = find_client(message.to.strip.to_s)
        connection_store[:opened_chats][client].delete(chat_id)

        send_message 'app.chat.destroyMultichat', chat_id: chat_id
    end

    def update_attendants_in_multichat(message, chat_id)
        client = find_client(message.to.strip.to_s)
        added = message.first_element('added')
        removed = message.first_element('removed')

        contacts = connection_store[:opened_chats][client][chat_id][:attendants]
        contacts -= xml_contacts_to_array(removed)
        contacts += xml_contacts_to_array(added)

        connection_store[:opened_chats][client][chat_id][:attendants] = contacts

        if contacts.empty?
            destroy_multichat(message, chat_id)
        else
            contacts.each do |contact|
                client.send(MessageBuilder::send_multichat_contacts(client.jid.strip.to_s, contact, chat_id, contacts))
            end
        end
    end
end