#include "ximethod.h"
#include "xicontext.h"


QValueList<SupportAttr> XIMethod::_attr_list = QValueList<SupportAttr>();

XIMethod::XIMethod()
{
  _imlist.setAutoDelete(TRUE);
}


void
XIMethod::initSuppIMAttr()
{
  if ( !_attr_list.isEmpty() ) return;
  
  _attr_list.append(SupportAttr(0, XNQueryInputStyle, TYPE_XIMSTYLES));
  Q_ASSERT(_attr_list.count() == 1);
}


QValueList<SupportAttr>
XIMethod::getSuppIMAttr()
{
  if ( _attr_list.isEmpty() ) initSuppIMAttr();
  return _attr_list;
}


QValueList<SupportAttr>
XIMethod::getSuppICAttr() 
{ 
  return XIContext::getSuppICAttr(); 
}


void
XIMethod::connectIM(Window w, QDataStream::ByteOrder b)
{
  _imlist.replace((long)w, new XIMAttribute(w, b)); 
  qDebug("connect IM (client communication window:%d)  number of IMs:%d", w, _imlist.count());
}


// Disconnect IM whose ID is zero
void
XIMethod::disconnectIM()
{
  for (QIntDictIterator<XIMAttribute> it(_imlist); it.current(); ++it) {
    if ( ! (*it).im() ) {
      qDebug("disconnect IM (client communication window:%d)", it.currentKey());
      _imlist.remove(it.currentKey());
    }
  }
  qDebug("number of IMs:%d", _imlist.count());
}


ushort 
XIMethod::createIM(Window w)
{
  ushort newim = 1;    // 1 origin
  for (;;) {
    if ( !takeIMAttr(newim) ) break;
    newim++;
  }

  XIMAttribute* pxim = _imlist.find(w);
  Q_CHECK_PTR(pxim);
   
  pxim->setIM(newim);
  qDebug("create IM:%d", newim);
  return newim;
}


void
XIMethod::removeIM(ushort im)
{
  XIMAttribute* pxim = takeIMAttr(im);
  if ( !pxim ) {
    qDebug("Cannot remove IM:%d", im);
    return;
  }  
  
  pxim->setIM(0);   // zero means invalid IM
  qDebug("Remove IM:%d", im);
}


ushort
XIMethod::createXIC(ushort im)
{
  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->_xic.createIC() : 0;
}


void
XIMethod::removeXIC(ushort im, ushort ic)
{
  XIMAttribute* pxim = takeIMAttr(im);
  if ( !pxim ) return;
  
  pxim->_xic.removeIC(ic);
}


void
XIMethod::setICValue(ushort im, ushort ic, ushort id, const QByteArray& data)
{
  qDebug("%s: IM:%d IC:%d attributes-id:%d data-size:%d",
	 __FUNCTION__, im, ic, id, data.size());

  if (id == 0) {
    // case id:0   set Input style
    setInputStyle(im, data);
    return;
  } 
  
  XIMAttribute* pxim = takeIMAttr(im);
  if ( !pxim ) return;
  pxim->_xic.setValue(ic, id, data);
}


QByteArray 
XIMethod::getICValue(ushort im, ushort ic, ushort id)
{
  qDebug("%s: IM:%d IC:%d attributes-id:%d", __FUNCTION__, im, ic, id);
  
  if (id == 0) return getInputStyle(im);  // case id:0   get Input style

  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->_xic.getValue(ic, id) : QByteArray();
}


QString
XIMethod::fontPreedit(ushort im, ushort ic)
{
  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->_xic.fontPreedit(ic) : QString();
}


QPoint
XIMethod::spotPreedit(ushort im, ushort ic)
{
  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->_xic.spotPreedit(ic) : QPoint();
}


XIMAttribute*  
XIMethod::takeIMAttr(ushort im) const
{  
  for (QIntDictIterator<XIMAttribute> it(_imlist); it.current(); ++it) {
    if ((*it).im() == im) return it;
  }
  
  return NULL;
}


Window
XIMethod::commWin(ushort im) const
{
  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->commWin() : 0;
}


Window
XIMethod::focusWindow(ushort im, ushort ic) const
{
  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->_xic.focusWindow(ic) : 0;
}


QDataStream::ByteOrder
XIMethod::byteOrder(ushort im) const
{
  XIMAttribute* pxim = takeIMAttr(im);
  return pxim ? pxim->byteOrder() : QDataStream::LittleEndian;
}


void
XIMethod::setInputStyle(ushort im, const QByteArray& data) 
{
  XIMStyle s;
  QDataStream ds(data, IO_ReadOnly);
  ds.setByteOrder(byteOrder(im));
  Q_ASSERT(data.size() == sizeof(XIMStyle));

  ds >> s;
  qDebug("client supported styles:%x", s);
  Q_ASSERT(s == OverTheSpotStyle);
  s &= OverTheSpotStyle;
  qDebug("server supported styles:%x", s);

  XIMAttribute*  pxim = takeIMAttr(im);
  if ( pxim ) takeIMAttr(im)->setStyle(s);
}


QByteArray
XIMethod::getInputStyle(ushort im) const
{
  QByteArray ret(0);
  QDataStream ds(ret, IO_WriteOnly);
  ds.setByteOrder(byteOrder(im));

  XIMAttribute*  pxim = takeIMAttr(im);
  if ( pxim ) {
    ds << takeIMAttr(im)->style();
  }

  return ret;
}


void
XIMethod::setTriggerFlag(ushort im, ushort ic, bool b)
{
  XIMAttribute*  pxim = takeIMAttr(im);
  if ( pxim ) {
    pxim->_xic.setTriggerFlag(ic, b);
  }
}


bool
XIMethod::triggerFlag(ushort im, ushort ic) const
{
  XIMAttribute*  pxim = takeIMAttr(im);
  return pxim ? pxim->_xic.triggerFlag(ic) : FALSE;
}
