getRandomRGB = ->
  red = Math.floor(Math.random() * 128) + 64
  green = Math.floor(Math.random() * 128) + 64
  blue = Math.floor(Math.random() * 128) + 64
  [red, green, blue] = [red, green, blue].map (color) ->
    color.toString(16).replace('0x', '')
  "##{red}#{green}#{blue}"


try
  wamp = require '../src/wamp'
catch e
  try
    wamp = require '../lib/wamp'
  catch e2
    console.log 'node-simple-router must be installed for this to work'
    process.exit(-1)

wampRouter = wamp.createWampRouter()


class ChatManager extends wamp.WampClient

  users: []

  start: () =>
    @register "addUser", @addUser
    @register "deleteUser", @deleteUser
    @register "getUsersList", @getUsersList
    @register "modifyUser", @modifyUser

  getUsersList: () =>
    @users

  deleteUser: (userId) =>
    for userData, index in @users
      if userData?.id is userId
        @users.splice index, 1
        @publish "deletedUser", userId
        break

  modifyUser: (sessionId) =>
    selectedUsers = @users.filter (user) -> user.id is sessionId
    return unless selectedUsers.length is 1
    user = selectedUsers[0]
    user.color = getRandomRGB();
    @publish "modifiedUser", user
    user

  addUser: (name, sessionId) =>
    same_name = @users.filter (user) -> user.username.toLowerCase() is name.toLowerCase()
    if same_name.length isnt 0
      return code: -1, reason: 'Username already taken'
    else
      retObj = username: name, color: getRandomRGB(), roundtrip: 0.0, id: sessionId
      @publish "newUser", retObj
      @users.push retObj
      retObj.code = 0
      #retObj.list = [{username: user.username, color: user.color, roundtrip: user.roundtrip, id: user.id} for user in @users]
      console.log "User #{name} has joined the chat"
      return retObj


chatManager = new ChatManager url: 'ws://localhost:8000/wampchat', realm: 'wampchat'

###
socks = []
msgs = []

setKey = (sock, key, value) ->
  sock[key] = value

broadcastMsg = (msg) ->
  for sock in socks
    try
      sock.send msg if sock.readyState is 'open'
    catch e
      console.log "Error sending data to clients: #{e.message}"

  
broadcastChattersList = () ->
  lsocks = ({id: sock.id, color: sock.color, username: sock.username, currentRoundTrip: sock.currentRoundTrip} for sock in socks when sock.username)
  for sock in socks
    try
      sock.send(headers: {command: 'chatters-list', subcommand: 'init'}, body: lsocks) if sock.readyState is 'open'
    catch e
      console.log "Error sending data to clients: #{e.message}"

processMessage = (sock, msg) ->
  headers = msg.headers
  body = msg.body
  msgCommand = headers.command
  switch msgCommand
    when 'chat-message'
      broadcastMsg(msg)
    when 'set'
      key = headers.key
      value = body
      setKey(sock, key, value)
      if key is 'username'
        setImmediate ->
          broadcastMsg headers: server_chat_headers, body: "Say hi to #{value} who has joined the chat."
          broadcastChattersList()
      #if key is 'color'
      #  setImmdiate ->
      #    broadcastChattersList()
    when 'reset-color'
      key = 'color'
      value = getRandomRGB()
      setKey(sock, key, value)
      sock.send headers: {command: 'set', key: key}, body: value
      broadcastChattersList()
    else
      console.log("Received an unrecognized message: " + body)

getRandomRGB = ->
  red = Math.floor(Math.random() * 128) + 64
  green = Math.floor(Math.random() * 128) + 64
  blue = Math.floor(Math.random() * 128) + 64
  [red, green, blue] = [red, green, blue].map (color) ->
     color.toString(16).replace('0x', '')
  "##{red}#{green}#{blue}"
    
send_oldmsgs = (sock) ->
  for msg in msgs
    msg = JSON.parse msg
    sock.send msg #if msg.headers.command is 'chat-message'

garbage_collect = () ->
  for sock, index in socks
    if not sock.username
      socks.splice index, 1
      return broadcastChattersList()

server_chat_headers = from: 'SERVER', color: '#dd0000', command: 'chat-message'

wsserver = ws.createWebSocketServer (websock) ->
  nsr_sid = router.utils.getCookie(websock.request, 'nsr_sid').nsr_sid
  websock.id = if nsr_sid then "nsr-#{nsr_sid}--#{router.utils.uuid()}" else router.utils.uuid()
  websock.color = getRandomRGB()
  socks.push websock
  init_websock = (ws) ->
    setTimeout ( ->
      if (ws.readyState isnt 'open') and (ws.readyState isnt 'closed')
        console.log "websocket isnt ready to be initialized. Rescheduling..."
        return init_websock(ws)
      if ws.readyState isnt 'closed'
        headers = command: 'set', key: 'id'
        body = ws.id
        ws.send {headers, body}
        headers.key = 'color'
        body = ws.color
        ws.send {headers, body}
        send_oldmsgs(ws)
    ), 100
  init_websock websock
  #garbage_interval = setInterval garbage_collect, 1000
    
  websock.on 'data', (opcode, data) ->
    #console.log "Received from web client opcode: #{opcode} with data #{data}"
    parsed_data = JSON.parse data
    msgs.push data if parsed_data.headers.command is 'chat-message'
    processMessage websock, parsed_data

  websock.on 'heartbeat', (currentRoundTrip, currentTime) ->
    #console.log "Current roundtrip for websock #{websock.id}: #{currentRoundTrip}"
    broadcastChattersList()
    
  websock.on 'close', (code, reason) ->
    if websock.username
      setImmediate ->
        broadcastMsg headers: server_chat_headers, body: "#{websock.username} has left the chat."
        broadcastChattersList()
    for sock, index in socks
      if socks[index]?.id is websock.id
        socks.splice index, 1
    console.log "web socket closed with code #{if code then code else 'none'} owed to #{if reason then reason else 'no reason provided'}"


createProxy = (port) ->
  proxyServer = net.createServer (sock) ->
    console.log "Server raw socket connected."
    wsock = new ws.WebSocketClientConnection("ws://0.0.0.0:#{port + 1}")
    wsock.color = "#000000"

    wsock.on 'close', (code) ->
      console.log "Proxy WebSocket closed with code:", code

    wsock.on 'data', (opcode, data) ->
      #console.log "Received from web client opcode: #{opcode} with data #{data}"
      msg = JSON.parse data
      headers = msg.headers;
      body = msg.body;
      msgCommand = headers.command;
      if msgCommand is 'chat-message'
        sock.write "#{headers.from.replace(/\r/g, '').replace(/\n/g, '')}: #{body}\r\n", "utf8"
      if msgCommand is 'set'
        wsock[headers.key] = body

    sock.on 'error', (err) ->
      console.log "Error on raw socket:", err.message
      sock.destroy()

    sock.on 'end', ->
      console.log 'Server raw socket disconnected'
      wsock.close()

    sock.on 'data', (data) ->
      if wsock.readyState isnt 'open'
        return console.log "WebSocket closed, '#{data}' could not be sent."
      if not wsock.username
        msg = body: data.toString('utf8').replace(/\r/g, '').replace(/\n/g, ''), headers: {command: 'set', key: 'username'}
        wsock.send JSON.stringify msg
        wsock.username = data.toString('utf8')
      else
        msg = body: data.toString('utf8').replace(/\r/g, '').replace(/\n/g, ''), headers: {command: 'chat-message', from: wsock.username, color: wsock.color}
        if msg.body.match(/^quit/i)
          sock.write('Bye\r\n')
          wsock.close()
          return sock.end()
        setImmediate ->
          if wsock.readyState is 'open'
            wsock.send JSON.stringify msg

     sock.write("Please enter your name: ")


  proxyServer.listen port


###

module.exports = {wampRouter, chatManager}


