/*
 * File    : DoublePuzzle.java
 * Created : 20-apr-2001 10:31
 * By      : fbusquets
 *
 * JClic - Authoring and playing system for educational activities
 *
 * Copyright (C) 2000 - 2018 Francesc Busquets & Departament
 * d'Educacio de la Generalitat de Catalunya
 *
 * 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 (see the LICENSE file).
 */

package edu.xtec.jclic.activities.puzzles;

import edu.xtec.jclic.*;
import edu.xtec.jclic.automation.ActiveBagContentKit;
import edu.xtec.jclic.boxes.*;
import edu.xtec.jclic.media.EventSounds;
import edu.xtec.jclic.project.JClicProject;
import edu.xtec.util.JDomUtility;
import java.awt.*;
import java.awt.event.MouseEvent;

/**
 * @author Francesc Busquets ([email protected])
 * @version 13.08.28
 */
public class DoublePuzzle extends Activity implements ActiveBagContentKit.Compatible {

  /** Creates new DoublePuzzle */
  public DoublePuzzle(JClicProject project) {
    super(project);
    abc = new ActiveBagContent[1];
    boxGridPos = AB;
    dragCells = true;
  }

  @Override
  public void initNew() {
    super.initNew();
    abc[0] = ActiveBagContent.initNew(3, 2, 'A');
  }

  @Override
  public org.jdom.Element getJDomElement() {
    org.jdom.Element ex;
    if (abc[0] == null)
      return null;

    org.jdom.Element e = super.getJDomElement();

    e.addContent(abc[0].getJDomElement());

    ex = new org.jdom.Element(SCRAMBLE);
    ex.setAttribute(TIMES, Integer.toString(shuffles));
    e.addContent(ex);

    ex = new org.jdom.Element(LAYOUT);
    ex.setAttribute(POSITION, LAYOUT_NAMES[boxGridPos]);
    e.addContent(ex);
    return e;
  }

  @Override
  public void setProperties(org.jdom.Element e, Object aux) throws Exception {
    org.jdom.Element child;
    super.setProperties(e, aux);
    child = e.getChild(ActiveBagContent.ELEMENT_NAME);
    if (child != null)
      abc[0] = ActiveBagContent.getActiveBagContent(child, project.mediaBag);
    if (abc[0] == null)
      throw new IllegalArgumentException("Puzzle without data!");

    if ((child = e.getChild(SCRAMBLE)) != null)
      shuffles = JDomUtility.getIntAttr(child, TIMES, shuffles);

    if ((child = e.getChild(LAYOUT)) != null)
      boxGridPos = JDomUtility.getStrIndexAttr(child, POSITION, LAYOUT_NAMES, boxGridPos);
  }

  @Override
  public void setProperties(edu.xtec.jclic.clic3.Clic3Activity c3a) throws Exception {
    super.setProperties(c3a);
    abc[0] = c3a.createActiveBagContent(0);
    boxGridPos = c3a.graPos;
    abc[0].setBoxBase(c3a.getBoxBase(0));
    dragCells = true;
  }

  public int getMinNumActions() {
    if (abc[0] == null)
      return 0;
    return abc[0].getNumCells();
  }

  @Override
  public boolean hasRandom() {
    return true;
  }

  @Override
  public boolean shuffleAlways() {
    return true;
  }

  @Override
  public boolean helpSolutionAllowed() {
    return true;
  }

  public Activity.Panel getActivityPanel(PlayStation ps) {
    return new Panel(ps);
  }

  class Panel extends Activity.Panel {

    ActiveBoxBag bgA, bgB;

    protected Panel(PlayStation ps) {
      super(ps);
      bc = new BoxConnector(this);
    }

    public void clear() {
      if (bgA != null) {
        bgA.end();
        bgA = null;
      }
      if (bgB != null) {
        bgB.end();
        bgB = null;
      }
    }

    @Override
    public void buildVisualComponents() throws Exception {

      if (firstRun)
        super.buildVisualComponents();

      clear();

      if (abc[0] != null) {
        if (acp != null)
          acp.generateContent(new ActiveBagContentKit(abc[0].nch, abc[0].ncw, abc, false), ps);
        bgA = ActiveBoxGrid.createEmptyGrid(null, this, margin, margin, abc[0]);
        bgB = ActiveBoxGrid.createEmptyGrid(null, this, margin, margin, abc[0]);
        bgA.setContent(abc[0]);
        bgA.setVisible(true);
        bgB.setVisible(true);

        ActiveBox bgbA = bgA.getBackgroundActiveBox();
        ActiveBox bgbB = bgB.getBackgroundActiveBox();
        if (bgbA != null && bgbB != null)
          bgbB.exchangeContent(bgbA);

        invalidate();
      }
    }

    @Override
    public void initActivity() throws Exception {
      super.initActivity();

      if (!firstRun)
        buildVisualComponents();
      else
        firstRun = false;

      setAndPlayMsg(MAIN, EventSounds.START);
      if (bgA != null && bgB != null) {
        shuffle(new ActiveBoxBag[] { bgA }, true, true);
        if (useOrder)
          currentItem = bgA.getNextItem(-1);
        playing = true;
      }
    }

    public void render(Graphics2D g2, Rectangle dirtyRegion) {
      if (bgA != null)
        bgA.update(g2, dirtyRegion, this);
      if (bgB != null)
        bgB.update(g2, dirtyRegion, this);
      if (bc.active)
        bc.update(g2, dirtyRegion, this);
    }

    public Dimension setDimension(Dimension preferredMaxSize) {
      if (bgA == null || bgB == null || getSize().equals(preferredMaxSize))
        return preferredMaxSize;
      return BoxBag.layoutDouble(preferredMaxSize, bgA, bgB, boxGridPos, margin);
    }

    @Override
    public void processMouse(MouseEvent e) {
      ActiveBox bx1, bx2;
      Point p = e.getPoint();

      if (playing)
        switch (e.getID()) {
        case MouseEvent.MOUSE_PRESSED:
          ps.stopMedia(1);
          if (bc.active) {
            if (dragCells)
              bx1 = bc.getBox();
            else
              bx1 = bgA.findActiveBox(bc.origin);
            bc.end();
            bx2 = bgB.findActiveBox(p);
            if (bx1 != null && bx2 != null && bx2.isInactive()) {
              boolean ok = false;
              String src = bx1.getDescription() + " (" + bx1.idOrder + ")";
              String dest = "(" + bx2.idOrder + ")";
              if (bx1.getContent().isEquivalent(abc[0].getActiveBoxContent(bx2.idOrder), true)) {
                ok = true;
                bx1.exchangeContent(bx2);
                bx1.setVisible(false);
                if (useOrder)
                  currentItem = bgA.getNextItem(currentItem);
              }
              int cellsAtPlace = bgA.countInactiveCells();
              ps.reportNewAction(DoublePuzzle.this, ACTION_PLACE, src, dest, ok, cellsAtPlace);
              if (ok && cellsAtPlace == bgA.getNumCells())
                finishActivity(true);
              else
                playEvent(ok ? EventSounds.ACTION_OK : EventSounds.ACTION_ERROR);
            }
            repaint();
          } else {
            if ((bx1 = bgA.findActiveBox(p)) != null && !bx1.isInactive()
                && (!useOrder || bx1.idOrder == currentItem)) {
              if (dragCells)
                bc.begin(p, bx1);
              else
                bc.begin(p);
              if (!bx1.playMedia(ps))
                playEvent(EventSounds.CLICK);
            }
          }
          break;

        case MouseEvent.MOUSE_MOVED:
        case MouseEvent.MOUSE_DRAGGED:
          bc.moveTo(p);
          break;
        }
    }

    @Override
    public void showHelp() {
      if (!helpWindowAllowed() || bgA == null)
        return;
      HelpActivityComponent hac = null;
      if (showSolution) {
        hac = new HelpActivityComponent(this) {
          ActiveBoxBag abb = null;

          public void render(Graphics2D g2, Rectangle dirtyRegion) {
            if (abb != null)
              abb.update(g2, dirtyRegion, this);
          }

          @Override
          public void init() {
            abb = ActiveBoxGrid.createEmptyGrid(null, this, DEFAULT_MARGIN, DEFAULT_MARGIN, abc[0]);
            abb.setContent(abc[0]);
            abb.setVisible(true);
            Dimension size = bgA.getBounds().getSize();
            abb.setBounds(DEFAULT_MARGIN, DEFAULT_MARGIN, size.width, size.height);
            size.width += 2 * DEFAULT_MARGIN;
            size.height += 2 * DEFAULT_MARGIN;
            setPreferredSize(size);
            setMaximumSize(size);
            setMinimumSize(size);
            Point p = (Point) getClientProperty(HelpActivityComponent.PREFERRED_LOCATION);
            if (p != null)
              p.translate((int) bgA.x - DEFAULT_MARGIN, (int) bgA.y - DEFAULT_MARGIN);
          }

          @Override
          public void processMouse(MouseEvent e) {
            ActiveBox bx;
            if (abb != null)
              switch (e.getID()) {
              case MouseEvent.MOUSE_PRESSED:
                bx = abb.findActiveBox(e.getPoint());
                if (bx != null) {
                  boolean m = bx.playMedia(ps);
                  markBox(bgB.getActiveBox(bx.idLoc), false);
                  if (!m)
                    playEvent(EventSounds.CLICK);
                }
                break;
              case MouseEvent.MOUSE_RELEASED:
                unmarkBox();
                break;
              }
          }
        };
        hac.init();
      }
      if (ps.showHelp(hac, helpMsg))
        ps.reportNewAction(getActivity(), ACTION_HELP, null, null, false, bgA.countInactiveCells());
      if (hac != null)
        hac.end();
    }
  }
}