/* machmgr.c
 *
 * Omnitty SSH Multiplexer
 * Copyright (c) 2004 Bruno Takahashi C. de Oliveira
 * All rights reserved.
 *
 * LICENSE INFORMATION:
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 * Copyright (c) 2002 Bruno T. C. de Oliveira
 */

#include "machmgr.h"
#include "curutil.h"
#include "machine.h"
#include "minibuf.h"
#include <string.h>
#include <stdlib.h>

#define MACHINE_MAX 256

/* List of machines */
static Machine *machs[MACHINE_MAX];
static int machcount = 0;
static int selmach = 0;    /* currently selected machine */
static int scrollpos = 0;  /* machine being shown at the top of the list */
static int vtrows, vtcols;
bool multicast = false;    /* whether keystrokes are sent to all tagged
                            * machines or not */
static WINDOW *listwin;

void machmgr_init(WINDOW *lw, int vtr, int vtc) {
   machcount = selmach = scrollpos = 0;
   vtrows = vtr, vtcols = vtc;
   listwin = lw;
}

static void machmgr_setselmach(int s) {
   int screenwidth, screenheight;
   getmaxyx(listwin, screenheight, screenwidth);

   selmach = s;

   /* clamp selmach to bounds */
   if (selmach >= machcount) selmach = machcount - 1;
   if (selmach < 0) selmach = 0;

   /* in particular, if machcount == 0, selmach will be 0 */

   /* correct scrolling if needed */
   if (machcount > 0) {
      if (selmach < scrollpos) scrollpos = selmach;
      if (selmach >= scrollpos + screenheight)
         scrollpos = selmach - screenheight + 1;
   }
}

static void machmgr_selmach_validate() {
   machmgr_setselmach(selmach);
}

void machmgr_draw_list() {
   unsigned char attr;
   const char *p;
   int w, h;
   int i, j;

   werase(listwin);
   getmaxyx(listwin, h, w);

   for (i = scrollpos; i < scrollpos + h && i < machcount; i++) {
      /* decide color */
      attr = machs[i]->alive ? 0x70 : 0x80;
      if (i == selmach)  attr &= 0xF0, attr |= 0x01; /* red background */
      if (machs[i]->tag) attr &= 0x0F, attr |= machs[i]->alive ? 0xA0 : 0x20;
                                                     /* green foreground */
      
      curutil_attrset(listwin, attr);
      wmove(listwin, i - scrollpos, 0);

      waddch(listwin, machs[i]->tag ? '*' : ' ');

      /* now we have to print the first w-2 characters of machs[i]->name,
       * padding with spaces at the end if necessary to complete w-2
       * characters. We say w-2 because one character of the width was
       * used up when printing '*' and another one must be left blank
       * at the end */
      p = machs[i]->name; j = w - 2;
      while (j--) {
         waddch(listwin, *p ? *p : ' ');
         if (*p) p++;
      }
   }
}

void machmgr_add(const char *machname) {
   if (!*machname) return;
   if (machcount >= MACHINE_MAX) return;
   machs[machcount++] = machine_new(machname, vtrows, vtcols);
   machmgr_selmach_validate();
}

static void machmgr_delete(int index) {
   int i;
   if (index < 0 || index >= machcount) return;

   machine_destroy(machs[index]);
   for (i = index; i < machcount - 1; i++) machs[i] = machs[i+1];
   machcount--;

   machmgr_selmach_validate();
}

void machmgr_delete_tagged() {
   int i, j;

   i = 0; /* next position in the vector we will write to */
   j = 0; /* next position in the vector we will look at in search
           * of nontagged machines */
   while (j < machcount) {
      /* advance j to the next untagged machine; finish if no such thing.
       * Delete tagged machines on the way. */
      while (j < machcount && machs[j]->tag) machine_destroy(machs[j++]);

      if (j >= machcount) break;  /* no more machines */
      machs[i++] = machs[j++];
   }
   
   machcount = i;
   machmgr_selmach_validate();
}

void machmgr_delete_current() {
   machmgr_delete(selmach);
}

static void make_vt_summary(RoteTerm *rt, char *buf, int len) {
   int r = rt->crow, c = rt->ccol;
   int i;

   buf[len-1] = 0;
   for (i = len - 2; i >= 0; i--) {
      if (r > 0) {
         buf[i] = rt->cells[r][c].ch;
         if ((buf[i] >= 0 && buf[i] < 32) || buf[i] == 127) buf[i] = 32;
      }
      else buf[i] = 32;
      
      if (--c < 0) {
         r--, c = rt->cols - 1;
         if (r > 0) while (c > 0 && rt->cells[r][c-1].ch == 32) c--;
      }
   }
}

void machmgr_draw_summary(WINDOW *w) {
   int i;
   int sumheight, sumwidth;
   char sumbuf[80];
   werase(w);
   wmove(w, 0, 0);
   getmaxyx(w, sumheight, sumwidth);
   
   for (i = scrollpos; i < scrollpos + sumheight && i < machcount; i++) {
      curutil_attrset(w, 0x80);
      wmove(w, i - scrollpos, 0);

      make_vt_summary(machs[i]->vt, sumbuf, sumwidth);
      waddstr(w, sumbuf);
   }
}

void machmgr_draw_vt(WINDOW *w) {
   werase(w);
   if (selmach >= 0 && selmach < machcount)
      rote_vt_draw(machs[selmach]->vt, w, 0, 0, NULL);
}

void machmgr_update() {
   int i;
   for (i = 0; i < machcount; i++)
      rote_vt_update(machs[i]->vt);
}

void machmgr_rename(char *newname) {
   machine_rename(machs[selmach], newname);
   machmgr_update();
}

void machmgr_prev_machine() {
   machmgr_setselmach(selmach - 1);
}

void machmgr_next_machine() {
   machmgr_setselmach(selmach + 1);
}

void machmgr_forward_keypress(int k) {
   int i;

   if (multicast) {
      for (i = 0; i < machcount; i++)
         if (machs[i]->tag) rote_vt_keypress(machs[i]->vt, k);
   }
   else if (selmach >= 0 && selmach < machcount)
      rote_vt_keypress(machs[selmach]->vt, k);
}

void machmgr_handle_death(pid_t p) {
   int i;
   for (i = 0; i < machcount; i++) {
      if (machs[i]->pid == p) {
         machs[i]->alive = false;
         rote_vt_forsake_child(machs[i]->vt);
      }
   }
}

void machmgr_toggle_multicast() {
   multicast = !multicast;
}

bool machmgr_is_multicast() {
   return multicast;
}

void machmgr_toggle_tag_current() {
   if (selmach >= 0 && selmach < machcount)
      machs[selmach]->tag = !machs[selmach]->tag;
}

void machmgr_delete_all() {
   int i;
   for (i = 0; i < machcount; i++) machine_destroy(machs[i]);
   machcount = selmach = scrollpos = 0;
}

void machmgr_tag_all(bool ignore_dead) {
   int i;
   for (i = 0; i < machcount; i++)
      machs[i]->tag = (!ignore_dead || machs[i]->alive);
}

void machmgr_untag_all() {
   int i;
   for (i = 0; i < machcount; i++) machs[i]->tag = false;
}

void machmgr_delete_dead() {
   int i;
   for (i = machcount - 1; i >= 0; i--)
      if (!machs[i]->alive) machmgr_delete(i);
}



syntax highlighted by Code2HTML, v. 0.9.1