import * as WebSocket from 'ws';
import PublicClient from './clients/types/publicClient';
import PrivateClient from './clients/types/privateClient';
import CustomClient from './clients/types/customClient';
import ChannelManager from './channelManager';

var logger = require('./logger');

class ClientManager {
  clients: PublicClient[]|PrivateClient[]|CustomClient[] = [];

  constructor() {
    //...maybe one day
  }

  addClient(data: any, channelManager: ChannelManager, ws: WebSocket) {
    if (data.client_type && !this.clientExists(data.user_id)) {
      var client = this.getClientType(data, channelManager, ws);
      this.clients.push(client);
      logger.accessLog.info(`client added to client manager: ${data.user_id}`);
      return client;
    } else {
      logger.accessLog.info(`no client type designated or client already exists, socket disconnected: ${data.user_id}`);
      ws.close();
      return null;
    }
  }

  clientsOfType(client_type: string) {
    var result: PublicClient[]|PrivateClient[]|CustomClient[] = [];

    for (let client of this.clients) {
      if (client.type() == client_type) {
        result.push(client);
      }
    }

    return result;
  }

  clientExists(id: number) {
    for (let client of this.clients) {
      if (client.id == id) {
        return client;
      }
    }

    return null;
  }

  getClient(id: number) {
    return this.clientExists(id);
  }

  removeClient(id: number) {
    var index: number = 0;

    for (let client of this.clients) {
      if (client.id == id) {
        client.ws.close();
        this.clients.splice(index, 1);
        logger.accessLog.info(`client disconnected: ${client.id}`);
        return true;
      }

      index++;
    }
  }

  getClientType(data: any, channelManager: ChannelManager, ws: WebSocket) {
    var client_type = data.client_type + 'Client'

    try {
      var Client = require(`./clients/types/${client_type}`);
      logger.accessLog.info(`attempting to create client of type ${data.client_type}, client id: ${data.user_id}...`);
      return new Client(data, ws, channelManager, this);
    } catch (e) {
      logger.errorLog.info(e);
      logger.accessLog.info(`creating base client: ${data.user_id}`);
      return new PublicClient(data, ws, channelManager, this);
    }
  }
};

export default ClientManager;