//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <WScom.h>
#include <WSCpopupMenu.h>
#include <WSCclassInformation.h>
#include <WSDmouse.h>
#include <WSDfont.h>
#include <WSCfontSet.h>
#include <WSDappDev.h>
#include <WSCnwbase.h>

WSCpopupMenu* WSCpopupMenu::_popuped_instance = NULL;

WSMFguiClassInitialize(WSCpopupMenu,WSCpulldownMenuPopup);

WSCpopupMenu::WSCpopupMenu(WSCbase* base,char* objname):
                WSCpulldownMenuPopup(base,objname){
  _press_state = 0;
  _client = NULL;
  _grabed = 0;
  WSMFpropertyCreateStart
    WSMFpropertyCreate(WSNclient,void*, _client,WSSclient );
  WSMFpropertyCreateEnd
}
WSMFproperty( WSCpopupMenu, WSNclient, void*, _client, NULL);
void WSCpopupMenu::setWorkWSNclient(void* data){}
void WSCpopupMenu::getWorkWSNclient(void** data){}

WSCpopupMenu::~WSCpopupMenu(){
  if (_popuped_instance == this){
    _popuped_instance = NULL;
  }
  long i;
  long num = _client_list.getNum();
  for(i=0; i<num; i++){
    WSCbase* client = (WSCbase*)_client_list[i];

    client->setUserData("PM-RGST",(void*)0);
    client->setUserData("PM-SERVER",(void*)0);
    WSCprocedure* op1 = (WSCprocedure*)client->getUserData("PM-BTNPRESS");
    if (op1 != NULL){
      client->delProcedure(op1);
      delete op1;
    }
    WSCprocedure* op2 = (WSCprocedure*)client->getUserData("PM-BTNRELEASE");
    if (op2 != NULL){
      client->delProcedure(op2);
      delete op2;
    }

    WSCprocedure* op3 = (WSCprocedure*)client->getUserData("PM-BTNMOVE");
    if (op3 != NULL){
      client->delProcedure(op3);
      delete op3;
    }

    WSCprocedure* op4 = (WSCprocedure*)client->getUserData("PM-DELETE");
    if (op4 != NULL){
      client->delProcedure(op4);
      delete op4;
    }
  }
}
void WSCpopupMenu::onActivate(){
  execProcedure(WSEV_ACTIVATE);
}
long WSCpopupMenu::popup(){
  if (_popuped_instance != NULL){
    return WS_ERR;
  }else{
    _popuped_instance = this;
  }
  onActivate();
  short px, py;
  WSCbool ret = WSGIappMouse()->getMousePosition(&px, &py);
  if (ret == False){
    return WS_ERR;
  }

  WSCushort st = _shadow_thick;
  if (WSGIappDev()->getGuiPolicy() & WS_POLICY_WINDOWS){
    st = 2;
    _shadow_thick = 2;
  }    
  WSCstring str( getProperty(WSNmenuItems) );  

  long num = str.getWords(",");    

  short len = 0;
  short ww = 0;
  short hh = st*2;

  WSDfont* fn = WSGIappFontSet()->getFont(getFontNo());
  WSCushort h = getItemHeight();
  WSCbool cascaded = False;

  for (short i=0; i<(short)num; i++) {
    WSCstring item = str.getWord(i, ",");
    WSCstring itemName = item.getWord(0, ":");
    WSCstring itemPrc = item.getWord(1, ":");

    if (!strcmp(itemName.getString(),"SP") ||
          !strcmp(itemName.getString(),"SEPARATOR")){
      hh += st*2;
      if (WSGIappDev()->getGuiPolicy() & WS_POLICY_WINDOWS){
        hh += 4;
      }
    }else{
      if ( !strncmp(itemPrc.getString(),"{",1) ){
        cascaded = True;
        long wpos = itemPrc.getWordCharPos(i, ",");
        WSCstring tmp(str.getString());
        tmp.deleteChars(0,wpos);
        wpos = tmp.getWordCharPos(1,"{");
        tmp.deleteChars(0,wpos);
        char* tstr = tmp.getString(WS_EN_UTF8);
        long len = strlen(tstr);
        long num_of_conma = 0;
        long j;
        long layers = 0;
        for(j=0; j< len; j++){
          if (tstr[j] == '}'){
            if (layers == 0){
              tstr[j] = 0;
              break;
            }else{
              layers--;
            }
          }
          if (tstr[j] == '{'){
            layers++;
          }
          if (tstr[j] == ','){
            num_of_conma++;
          }
        }
        i += num_of_conma;
      }
      hh += h;
    }

    if (len < (short)strlen(itemName.getString())) {
      len = (short)strlen(itemName.getString());
      WSCstring space(" ");
      WSCushort smargin = WSGIappFontSet()->getStringWidth(getFontNo(),&space);
      ww = (short)fn->getStringWidth(&itemName) + st * 2 + st * 2 + smargin;
    }
  }

  //矢印のスペースの確保
  if (cascaded != False){
      ww += 30;
  }

  if (px + ww > WSGIappDev()->getWidth()) {
    px -= (px + ww - WSGIappDev()->getWidth());
  }

  if (py + hh > WSGIappDev()->getHeight()) {
    py -= (py + hh - WSGIappDev()->getHeight());
  }

//WSMFtrace("WSCpopupMenu::popup %d %d %d %d   st=%d ih=%d\n",px,py,ww,hh,st,h+st*2);

  setPropertyV(WSNx,(short)px);
  setPropertyV(WSNy,(short)py);
//  setPropertyV(WSNmenuItemHeight,(WSCushort)(h + st*2));
  setPropertyV(WSNwidth,(WSCushort)(ww));
  setPropertyV(WSNheight,(WSCushort)(hh));
  setVisible(True);

  return WS_NO_ERR;
}

long WSCpopupMenu::popdown(){
  if (_popuped_instance == this){
    _popuped_instance = NULL;
  }
  setVisible(False);
  _selected = False;
  _client = NULL;
  return WS_NO_ERR;
}

long WSCpopupMenu::popdownAndExecute(){
  if (_popuped_instance == this){
    _popuped_instance = NULL;
  }
  _press_state = 0;
  setVisible(False);
  if (strcmp(getProcName(),"")){
    execProcedure(getProcName());
  }
  _selected = False;
  _client = NULL;
  return WS_NO_ERR;
}

long WSCpopupMenu::registerClient(WSCbase* client,WSCbool recursive){
  long registered = (long)client->getUserData("PM-RGST");
  if (registered == 1){
    return WS_NO_ERR;
  }

  _client_list.add((void*)client);

  client->setUserData("PM-RGST",(void*)1);
  client->setUserData("PM-SERVER",(void*)this);

  long trg1 = WSEV_MOUSE_PRESS;
  long trg2 = WSEV_MOUSE_RELEASE;
  long trg3 = WSEV_MOUSE_MOVE;

  WSCprocedure* btnpress = new WSCprocedure("PM_btn_press",trg1);
  btnpress->setFunction(_on_btn_press,"_on_btn_press");
  btnpress->setInternal(True);
  client->addProcedure(btnpress);
  client->setUserData("PM-BTNPRESS",(void*)btnpress);

  WSCprocedure* btnrelease = new WSCprocedure("PM_btn_release",trg2);
  btnrelease->setFunction(_on_btn_release,"_on_btn_release");
  btnrelease->setInternal(True);
  client->addProcedure(btnrelease);
  client->setUserData("PM-BTNRELEASE",(void*)btnrelease);

  WSCprocedure* btnmove = new WSCprocedure("PM_btn_move",trg3);
  btnmove->setFunction(_on_btn_move,"_on_btn_move");
  btnmove->setInternal(True);
  client->addProcedure(btnmove);
  client->setUserData("PM-BTNMOVE",(void*)btnmove);

  WSCprocedure* idelete = new WSCprocedure("PM_idelete",WSEV_DELETE);
  idelete->setFunction(_on_delete,"_on_delete");
  idelete->setInternal(True);
  client->addProcedure(idelete);
  client->setUserData("PM-DELETE",(void*)idelete);

  if (recursive != False){
    long val =(long)recursive;
    client->setUserData("PM-RECURSIVE",(void*)val);
    WSClistData children = client->getChildren();
    long i,num;
    num = children.getNum();
    for(i=0; i<num; i++){
      WSCbase* child = (WSCbase*)children[i];
      if (child->getObjectType() & WS_TYPE_MANAGER){
        _registerClient(child,True);
      }
    } 
  }
  return WS_NO_ERR;
}
long WSCpopupMenu::_registerClient(WSCbase* client,WSCbool recursive){
  long registered = (long)client->getUserData("PM-RGST");
  if (registered == 1){
    return WS_NO_ERR;
  }

  _client_list.add((void*)client);

  client->setUserData("PM-RGST",(void*)1);
  client->setUserData("PM-SERVER",(void*)this);

  long trg1 = WSEV_MOUSE_PRESS;
  long trg2 = WSEV_MOUSE_RELEASE;
  long trg3 = WSEV_MOUSE_MOVE;

  WSCprocedure* btnpress = new WSCprocedure("PM_btn_press",trg1);
  btnpress->setFunction(_on_btn_press_recursive,"_on_btn_press_recursive");
  btnpress->setInternal(True);
  client->addProcedure(btnpress);
  client->setUserData("PM-BTNPRESS",(void*)btnpress);

  WSCprocedure* btnrelease = new WSCprocedure("PM_btn_release",trg2);
  btnrelease->setFunction(_on_btn_release_recursive,"_on_btn_release_recursive");
  btnrelease->setInternal(True);
  client->addProcedure(btnrelease);
  client->setUserData("PM-BTNRELEASE",(void*)btnrelease);

  WSCprocedure* btnmove = new WSCprocedure("PM_btn_move",trg3);
  btnmove->setFunction(_on_btn_move_recursive,"_on_btn_move_recursive");
  btnmove->setInternal(True);
  client->addProcedure(btnmove);
  client->setUserData("PM-BTNMOVE",(void*)btnmove);

  WSCprocedure* idelete = new WSCprocedure("PM_idelete",WSEV_DELETE);
  idelete->setFunction(_on_delete,"_on_delete");
  idelete->setInternal(True);
  client->addProcedure(idelete);
  client->setUserData("PM-DELETE",(void*)idelete);


  if (recursive != False){
    long val =(long)recursive;
    client->setUserData("PM-RECURSIVE",(void*)val);
    WSClistData children = client->getChildren();
    long i,num;
    num = children.getNum();
    for(i=0; i<num; i++){
      WSCbase* child = (WSCbase*)children[i];
      if (child->getObjectType() & WS_TYPE_MANAGER){
        _registerClient(child,True);
      }
    } 
  }
  return WS_NO_ERR;
}

long WSCpopupMenu::unregisterClient(WSCbase* client){
  _client_list.del((void*)client);
  long registered = (long)client->getUserData("PM-RGST");
  long val =(long)client->getUserData("PM-RECURSIVE");
  WSCpopupMenu* serv = (WSCpopupMenu*)client->getUserData("PM-SERVER");

  if (registered == 1 && serv == this){
    client->setUserData("PM-RGST",(void*)0);
    client->setUserData("PM-SERVER",(void*)0);

    WSCprocedure* op1 = (WSCprocedure*)client->getUserData("PM-BTNPRESS");
    client->delProcedure(op1);
    delete op1;

    WSCprocedure* op2 = (WSCprocedure*)client->getUserData("PM-BTNRELEASE");
    client->delProcedure(op2);
    delete op2;

    WSCprocedure* op3 = (WSCprocedure*)client->getUserData("PM-BTNMOVE");
    client->delProcedure(op3);
    delete op3;

    WSCprocedure* op4 = (WSCprocedure*)client->getUserData("PM-DELETE");
    client->delProcedure(op4);
    delete op4;

    if( val != False){
      client->setUserData("PM-RECURSIVE",(void*)0);
      WSClistData children = client->getChildren();
      long i,num;
      num = children.getNum();
      for(i=0; i<num; i++){
        WSCbase* child = (WSCbase*)children[i];
        if (child->getObjectType() & WS_TYPE_MANAGER){
          unregisterClient(child);
        }
      } 
    }
  }
  return WS_NO_ERR;
}

void WSCpopupMenu::_on_delete(WSCbase* client){
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  if (obj == NULL){
    return;
  }
  obj->unregisterClient(client);
}
void WSCpopupMenu::_on_btn_press(WSCbase* client){
//printf("WSCpopupMenu::_on_btn_press press... client=%s\n",client->getInstanceName());
  if (_popuped_instance != NULL){
    return;
  }
  if (WSGIappMouse()->getTargetBtn() != WS_MOUSE_BTN3){
    return;
  }
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  if (obj == NULL){
    return;
  }
  if (client->getSensitive() == False){
    return;
  }
  if (obj->_press_state != False){
    return;
  }

  client->setUserData("PM-POPUP",(void*)1);
  obj->_press_state = True;
  WSCnwbase* vpbase = (WSCnwbase*)client->cast("WSCnwbase");
  if (vpbase != NULL){
    if (vpbase->getOutSideMousePress() == False){
      vpbase->setOutSideMousePress(True);
      vpbase->setUserData("OSMP-ch",(void*)1);
    }
    if (vpbase->getOutSideMouseMove() == False){
      vpbase->setOutSideMouseMove(True);
      vpbase->setUserData("OSMM-ch",(void*)1);
    }
    if (vpbase->getOutSideMouseRelease() == False){
      vpbase->setOutSideMouseRelease(True);
      vpbase->setUserData("OSMR-ch",(void*)1);
    }
    if (vpbase->getMouseGrabed() == False){
      vpbase->setMouseGrabed(True);
      vpbase->setUserData("MG-ch",(void*)1);
    }
  }
  obj->_client = (void*)client;
  long ret = obj->popup();
  if (ret != WS_ERR){
    client->setUserData(WS_PM_POPUPED,(void*)1);
  }
}



void WSCpopupMenu::_on_btn_release(WSCbase* client){
//printf("popupmenu: btn release client=%s\n",client->getInstanceName());
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  if (obj == NULL){
    return;
  }
  if (obj->getVisible() == False){
    return;
  }
  if (obj->_grabed == 0){
    if (WSGIappMouse()->getTargetBtn() != WS_MOUSE_BTN3){
      return;
    }
  }

  if (obj->_grabed == 0 && obj->_selected == False){
    WSDdev* dev = client->getowndev();
//WSMFtrace("WSCpopupMenu::_on_btn_release here----------- client=%s\n",client->getInstanceName()); 
    if (client->cast("WSCnwbase")!=0){
      dev = client->getParentDev();
    }
    if (dev != NULL){
//WSMFtrace("WSCpopupMenu::_on_btn_release grabed  %s!!!!!!!!!!!!\n",dev->getClassName());
      obj->_modal_bk = WSGIappDev()->getModalClient();
      WSGIappDev()->setModalClient(client);
      WSCbool fl = True;
      dev->setValue(WSDEV_GRAB_POINTER,&fl);
      obj->_grabed = True;
      if (client->cast("WSCnwbase") != NULL){
        WSCnwbase* nwbase = (WSCnwbase*)client->cast("WSCnwbase");
        nwbase->setMouseGrabed(True);
      }
    }
//printf("popup:: grabed...\n");
    return;
  }else if (obj->_grabed != 0){
    WSCbool fl = False;
    WSDdev* dev = client->getdev();
    if (client->cast("WSCnwbase")!=0){
      dev = client->getParentDev();
    }
    if (dev != NULL){
//WSMFtrace("WSCpopupMenu::_on_btn_press grab -> false\n");
      WSGIappDev()->setModalClient(obj->_modal_bk);
      dev->setValue(WSDEV_GRAB_POINTER,&fl);
      obj->_grabed = False;
//printf("popup:: grabed canceled...\n");
    }
  } 
 
  if ((long)client->getUserData("PM-POPUP") == 0){
    return;
  }
  WSCnwbase* vpbase = (WSCnwbase*)client->cast("WSCnwbase");
  if (vpbase != NULL){
    if ((long)vpbase->getUserData("OSMP-ch") == 1){
      vpbase->setOutSideMousePress(False);
      vpbase->setUserData("OSMP-ch",(void*)0);
    }
    if ((long)vpbase->getUserData("OSMM-ch") == 1){
      vpbase->setOutSideMouseMove(False);
      vpbase->setUserData("OSMM-ch",(void*)0);
    }
    if ((long)vpbase->getUserData("OSMR-ch") == 1){
      vpbase->setOutSideMouseRelease(False);
      vpbase->setUserData("OSMR-ch",(void*)0);
    }
    if ((long)vpbase->getUserData("MG-ch") == 1){
      vpbase->setMouseGrabed(False);
      vpbase->setUserData("MG-ch",(void*)0);
    }
  }
  client->setUserData(WS_PM_POPUPED,(void*)0);
  obj->popdownAndExecute();
//printf("popup:: popdown...\n");
}

void WSCpopupMenu::_on_btn_move(WSCbase* client){
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  if (obj == NULL){
    return;
  }
//WSMFtrace("WSCpopupMenu::_on_btn_move()  grabed=%d\n",obj->_grabed);
  if (obj->_grabed == False){
    if (WSGIappMouse()->getTargetBtn() != WS_MOUSE_BTN3){
      return;
    }
  }
  if ((long)client->getUserData("PM-POPUP") == 0){
    return;
  }
  short x, y;
  WSCbool ret = WSGIappMouse()->getMousePosition(&x, &y);
  if (ret != False){
    obj->setAbsoluteDraw(True);
    obj->draw();
  }
}

void WSCpopupMenu::_on_btn_press_recursive(WSCbase* client){
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  WSCbase* parent = client->getParent();
  if (parent != NULL){
    WSCpopupMenu* obj2 = (WSCpopupMenu*)parent->getUserData("PM-SERVER");
    if (obj == obj2){
      parent->execProcedure("PM_btn_press");
    }
  }
}
void WSCpopupMenu::_on_btn_release_recursive(WSCbase* client){
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  WSCbase* parent = client->getParent();
  if (parent != NULL){
    WSCpopupMenu* obj2 = (WSCpopupMenu*)parent->getUserData("PM-SERVER");
    if (obj == obj2){
      parent->execProcedure("PM_btn_release");
    }
  }
}
void WSCpopupMenu::_on_btn_move_recursive(WSCbase* client){
  WSCpopupMenu* obj = (WSCpopupMenu*)client->getUserData("PM-SERVER");
  WSCbase* parent = client->getParent();
  if (parent != NULL){
    WSCpopupMenu* obj2 = (WSCpopupMenu*)parent->getUserData("PM-SERVER");
    if (obj == obj2){
      parent->execProcedure("PM_btn_move");
    }
  }
}



