/*
 * dselect - Debian GNU/Linux package maintenance user interface
 * methlist.cc - list of access methods and options
 *
 * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
 *
 * This 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,
 * or (at your option) any later version.
 *
 * This 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; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <string.h>
#include <ncurses.h>
#include <assert.h>
#include <signal.h>

extern "C" {
#include "config.h"
#include "dpkg.h"
#include "dpkg-db.h"
}
#include "dselect.h"
#include "bindings.h"
#include "method.h"
#include "helpmsgs.h"

static keybindings methodlistbindings(methodlist_kinterps,methodlist_korgbindings);

const char *methodlist::itemname(int index) {
  return table[index]->name;
}

void methodlist::kd_abort() { }

void methodlist::kd_quit() {
  if (debug) fprintf(debug,"methodlist[%p]::kd_quit() setting coption=%p\n",
                     this, table[cursorline]);
  coption= table[cursorline];
}

void methodlist::setwidths() {
  if (debug) fprintf(debug,"methodlist[%p]::setwidths()\n",this);

  status_width= 1;
  gap_width= 1;
  name_width= 14;
  name_column= status_width + gap_width;
  description_column= name_column + name_width + gap_width;

  total_width= TOTAL_LIST_WIDTH;
  description_width= total_width - description_column;
}

void methodlist::redrawtitle() {
  if (title_height) {
    mywerase(titlewin);
    mvwaddnstr(titlewin,0,0,"dselect - list of access methods",xmax);
    wnoutrefresh(titlewin);
  }
}

void methodlist::redrawthisstate() {
  if (!thisstate_height) return;
  mywerase(thisstatepad);
  wprintw(thisstatepad,
          "Access method `%s'.",
          table[cursorline]->name);
  pnoutrefresh(thisstatepad, 0,0, thisstate_row,0,
               thisstate_row, lesserint(total_width - 1, xmax - 1));
}

void methodlist::redraw1itemsel(int index, int selected) {
  int i;
  const char *p;

  wattrset(listpad, selected ? listsel_attr : list_attr);
  mvwaddch(listpad,index,0,
           table[index] == coption ? '*' : ' ');
  wattrset(listpad, selected ? listsel_attr : list_attr);
  mvwprintw(listpad,index,name_column-1, " %-*.*s ",
            name_width, name_width, table[index]->name);
  
  i= description_width;
  p= table[index]->summary ? table[index]->summary : "";
  while (i>0 && *p && *p != '\n') {
    waddch(listpad,*p);
    i--; p++;
  }
  while (i>0) {
    waddch(listpad,' ');
    i--;
  }
}

void methodlist::redrawcolheads() {
  if (colheads_height) {
    wattrset(colheadspad,colheads_attr);
    mywerase(colheadspad);
    mvwaddstr(colheadspad,0,0, "  ");
    mvwaddnstr(colheadspad,0,name_column, "Abbrev.", name_width);
    mvwaddnstr(colheadspad,0,description_column, "Description", description_width);
  }
  refreshcolheads();
}

methodlist::methodlist() : baselist(&methodlistbindings) {
  if (debug)
    fprintf(debug,"methodlist[%p]::methodlist()\n",this);

  table= new struct option*[noptions];

  struct option *opt, **ip;
  for (opt=options, ip=table, nitems=0; opt; opt=opt->next, nitems++) *ip++= opt;
  assert(nitems==noptions);

  setcursor(0);

  if (debug)
    fprintf(debug,"methodlist[%p]::methodlist done; noptions=%d\n", this, noptions);
}

methodlist::~methodlist() {
  if (debug) fprintf(debug,"methodlist[%p]::~methodlist()\n",this);
  delete[] table;
}

quitaction methodlist::display() {
  int response;
  const keybindings::interpretation *interp;

  if (debug) fprintf(debug,"methodlist[%p]::display()\n",this);

  setupsigwinch();
  startdisplay();
  
  if (debug) fprintf(debug,"methodlist[%p]::display() entering loop\n",this);
  for (;;) {
    if (whatinfo_height) wcursyncup(whatinfowin);
    if (doupdate() == ERR) ohshite("doupdate failed");
    signallist= this;
    if (sigprocmask(SIG_UNBLOCK,&sigwinchset,0)) ohshite("failed to unblock SIGWINCH");
    response= getch();
    if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to re-block SIGWINCH");
    if (response == ERR) ohshite("getch failed");
    interp= (*bindings)(response);
    if (debug)
      fprintf(debug,"methodlist[%p]::display() response=%d interp=%s\n",
              this,response, interp ? interp->action : "[none]");
    if (!interp) { beep(); continue; }
    (this->*(interp->mfn))();
    if (interp->qa != qa_noquit) break;
  }
  pop_cleanup(ehflag_normaltidy); // unset the SIGWINCH handler
  enddisplay();
  
  if (debug) fprintf(debug,"methodlist[%p]::display() done\n",this);

  return interp->qa;
}

void methodlist::itd_description() {
  whatinfovb("explanation of ");
  whatinfovb(table[cursorline]->name);

  wattrset(infopad,info_headattr);
  waddstr(infopad, table[cursorline]->name);
  waddstr(infopad," - ");
  waddstr(infopad, table[cursorline]->summary);
  wattrset(infopad,info_attr);

  const char *m= table[cursorline]->description;
  if (!m || !*m) m= "No explanation available.";
  waddstr(infopad,"\n\n");
  wordwrapinfo(0,m);
}

void methodlist::redrawinfo() {
  if (!info_height) return;
  whatinfovb.reset();
  werase(infopad); wmove(infopad,0,0);
  
  if (debug) fprintf(debug,"methodlist[%p]::redrawinfo()\n", this);

  itd_description();

  whatinfovb.terminate();
  int y,x;
  getyx(infopad, y,x);
  if (x) y++;
  infolines= y;

  refreshinfo();
}

const struct helpmenuentry *methodlist::helpmenulist() {
  static const struct helpmenuentry list[]= {
    { 'i', &hlp_methintro            },
    { 'k', &hlp_methkeys             },
    {  0                             }
  };
  return list;
};
