
/* 
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. 
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information. 
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-* 
-* 
-*
Z* -------------------------------------------------------------------
*/
#include"os_python.h"

#include"os_predef.h"
#include"os_std.h"
#include"os_gl.h"

#include"main.h"
#include"Feedback.h"
#include"Rep.h"
#include"MemoryDebug.h"
#include"CoordSet.h"
#include"P.h"
#include"Util.h"
#include"Scene.h"

/*========================================================================*/
/**
 * Delete this instance and return a newly created instance.
 *
 * If creating the new instance fails (e.g. empty rep):
 * - Don't delete this instance
 * - Set cs->Active[rep] to false
 *
 * @todo Use move semantics instead? Return false on failure?
 */
Rep* Rep::rebuild()
{
  assert(cs);
  assert(fNew);
  Rep* tmp = fNew(cs, getState());
  if (tmp) {
    tmp->fNew = fNew;
    delete this;
    return tmp;
  }

  // nothing returned -- visibility is zero...
  // keep the old object around, but inactive (TODO why?)
  cs->Active[type()] = false;
  return this;
}

/*========================================================================*/
/**
 * Rebuild if necessary (according to invalidation status). Returns either this
 * instance, or deletes this instance and returns a new one, or nullptr if the rep
 * became empty/inactive.
 */
Rep* Rep::update()
{
  assert(cs);

  if (MaxInvalid == cRepInvNone) {
    return this;
  }

  auto I = this;
  auto const rep = type();
  auto const* cs_ = cs;

  assert(cs_->Active[rep]);

  if (MaxInvalid == cRepInvPick) {
    switch (rep) {
    case cRepLine:
    case cRepCyl:
    case cRepRibbon:
    case cRepNonbonded:
      // TODO Is this needed? How about other pickable reps, like:
      // - cartoon
      // - spheres
      // - surface with pick_surface=on
      MaxInvalid = cRepInvRep;
    }
  }

  if (MaxInvalid < cRepInvColor) {
    // nothing to do
  } else if (MaxInvalid == cRepInvColor) {
    I = recolor();
  } else if (MaxInvalid > cRepInvVisib || !sameVis()) {
    I = rebuild();
  } else if (!sameColor()) {
    I = recolor();
  }

  if (!cs_->Active[rep]) {
    delete I;
    return nullptr;
  }

  if (I) {
    I->MaxInvalid = cRepInvNone;
  }

  return I;
}

/*========================================================================*/
/**
 * Request that the rep gets updated. Update happens on next scene redraw.
 *
 * @param level Invalidate to at least this level
 */
void Rep::invalidate(cRepInv_t level)
{
  auto I = this;
  SceneInvalidatePicking(I->G); // for now, if anything invalidated, then invalidate picking
  if(level > I->MaxInvalid)
    I->MaxInvalid = level;
}

/**
 * Get the visRep mask according to auto_show_* settings
 */
cRepBitmask_t RepGetAutoShowMask(PyMOLGlobals * G)
{
  cRepBitmask_t mask = 0;
  if (SettingGetGlobal_b(G, cSetting_auto_show_lines))     mask |= cRepLineBit;
  if (SettingGetGlobal_b(G, cSetting_auto_show_spheres))   mask |= cRepSphereBit;
  if (SettingGetGlobal_b(G, cSetting_auto_show_nonbonded)) mask |= cRepNonbondedBit;
  return mask;
}

/*========================================================================*/
/**
 * Derived classes should overrride this method.
 *
 * TODO: What is this default implementation useful for? Debugging?
 */
void Rep::render(RenderInfo* info)
{
  if(G->HaveGUI && G->ValidContext) {
#ifdef PURE_OPENGL_ES_2
    /* TODO */
#else
    glBegin(GL_LINE_LOOP);
    glVertex3f(-0.5F, -0.5F, -0.5F);
    glVertex3f(-0.5F, -0.5F, 0.5F);
    glVertex3f(-0.5F, 0.5F, 0.5F);
    glVertex3f(-0.5F, 0.5F, -0.5F);

    glVertex3f(0.5F, 0.5F, -0.5F);
    glVertex3f(0.5F, 0.5F, 0.5F);
    glVertex3f(0.5F, -0.5F, 0.5F);
    glVertex3f(0.5F, -0.5F, -0.5F);
    glEnd();

    glBegin(GL_LINES);
    glVertex3i(0, 0, 0);
    glVertex3i(1, 0, 0);

    glVertex3i(0, 0, 0);
    glVertex3i(0, 2, 0);

    glVertex3i(0, 0, 0);
    glVertex3i(0, 0, 3);

    glEnd();
#endif
  }

}


/*========================================================================*/
Rep::Rep(pymol::CObject* obj_, int state)
    : G(obj_->G)
    , obj(obj_)
{
  context.object = obj_;
  context.state = state;
}

Rep::Rep(CoordSet* cs_, int state)
    : Rep(cs_->Obj, state)
{
  cs = cs_;
}

Rep::~Rep()
{
  FreeP(P);
}

RepIterator::RepIterator(PyMOLGlobals * G, int rep_) {
  if (rep_ < 0){
    end = cRepCnt;
    rep = -1;
  } else {
    end = rep_ + 1;
    rep = rep_ - 1;
  }
}
