org.rifidi.designer.library.retail.clothingrack.ClothingRack.java Source code

Java tutorial

Introduction

Here is the source code for org.rifidi.designer.library.retail.clothingrack.ClothingRack.java

Source

/*
 *  Clothing.java
 *
 *  Project:      RiFidi Designer - A Virtualization tool for 3D RFID environments
 *  http://www.rifidi.org
 *  http://rifidi.sourceforge.net
 *  Copyright:       Pramari LLC and the Rifidi Project
 *  License:      Lesser GNU Public License (LGPL)
 *  http://www.opensource.org/licenses/lgpl-license.html
 */
package org.rifidi.designer.library.retail.clothingrack;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EmptyStackException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.Callable;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.databinding.observable.list.IListChangeListener;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.rifidi.designer.entities.Entity;
import org.rifidi.designer.entities.VisualEntity;
import org.rifidi.designer.entities.annotations.Property;
import org.rifidi.designer.entities.databinding.IEntityObservable;
import org.rifidi.designer.entities.interfaces.IContainer;
import org.rifidi.designer.entities.interfaces.IProducer;
import org.rifidi.designer.entities.internal.RifidiTagWithParent;
import org.rifidi.designer.library.retail.Position;
import org.rifidi.designer.library.retail.clothing.Clothing;
import org.rifidi.designer.services.core.entities.EntitiesService;
import org.rifidi.services.annotations.Inject;
import org.rifidi.services.tags.IRifidiTagService;
import org.rifidi.services.tags.exceptions.RifidiTagNotAvailableException;
import org.rifidi.services.tags.model.IRifidiTagContainer;
import org.rifidi.tags.impl.RifidiTag;

import com.jme.bounding.BoundingBox;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.SharedNode;
import com.jme.scene.SwitchNode;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.shape.Box;
import com.jme.util.export.binary.BinaryImporter;

/**
 * A rack can contain multiple pieces of clothing.Handling is almost the same as
 * with the box producer.
 * 
 * @author Jochen Mader - jochen@pramari.com - Apr 3, 2008
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
public class ClothingRack extends VisualEntity
        implements IContainer, IEntityObservable, IRifidiTagContainer, PropertyChangeListener, IProducer<Clothing> {
    /** Logger for this class. */
    @XmlTransient
    private static final Log logger = LogFactory.getLog(ClothingRack.class);
    /** Container for entities inside the holder. */
    @XmlIDREF
    private List<VisualEntity> products;
    /** Capacity of the container. */
    private int capacity = 10;
    /** Number of items currently in the list. */
    private int itemCount = 0;
    /** Model for shared meshes */
    @XmlTransient
    private static Node[] lod = null;
    @XmlTransient
    private static Node clotModel = null;
    /** Node that contains the different lods. */
    @XmlTransient
    private SwitchNode switchNode;
    /** Set containing all available tags. */
    @XmlIDREF
    private List<RifidiTag> tags;
    @XmlTransient
    private Stack<RifidiTag> tagStack;
    /** List of wrapper objects that bind tags and container together. */
    @XmlTransient
    private WritableList wrappers;
    /** Reference to the tag service. */
    @XmlTransient
    private IRifidiTagService tagService;
    /** Reference to the entities service. */
    @XmlTransient
    private EntitiesService entitiesService;

    /**
     * Constructor.
     */
    public ClothingRack() {
        super();
        setName("Clothing rack");
        tags = new ArrayList<RifidiTag>();
        wrappers = new WritableList();
        tagStack = new Stack<RifidiTag>();
        products = new ArrayList<VisualEntity>();
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.entities.interfaces.IEntityObservable#
     * addListChangeListener
     * (org.eclipse.core.databinding.observable.list.IListChangeListener)
     */
    @Override
    public void addListChangeListener(IListChangeListener changeListener) {
        wrappers.addListChangeListener(changeListener);
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.entities.interfaces.IEntityObservable#
     * removeListChangeListener
     * (org.eclipse.core.databinding.observable.list.IListChangeListener)
     */
    @Override
    public void removeListChangeListener(IListChangeListener changeListener) {
        wrappers.removeListChangeListener(changeListener);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.Entity#destroy()
     */
    @Override
    public void destroy() {
        List<Entity> del = new ArrayList<Entity>();
        del.addAll(products);
        entitiesService.deleteEntities(del);
        for (RifidiTag tag : tags) {
            tagService.releaseRifidiTag(tag, this);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.Entity#init()
     */
    @Override
    public void init() {
        prepare();
        Node mainNode = new Node();
        mainNode.setModelBound(new BoundingBox());
        Node node = new Node("maingeometry");
        node.setModelBound(new BoundingBox());
        mainNode.attachChild(node);
        if (lod == null) {
            lod = new Node[3];
            URI modelpath = null;
            for (int count = 0; count < 3; count++) {
                try {
                    modelpath = getClass().getClassLoader()
                            .getResource("org/rifidi/designer/library/retail/clothingrack/rack" + count + ".jme")
                            .toURI();
                } catch (URISyntaxException e) {
                    logger.debug(e);
                }
                try {
                    lod[count] = (Node) BinaryImporter.getInstance().load(modelpath.toURL());
                    lod[count].setLocalRotation(
                            new Quaternion().fromAngleAxis(270 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X));
                    lod[count].setModelBound(new BoundingBox());
                    lod[count].setLocalScale(new Vector3f(0.87f, 1f, 1f));
                    lod[count].updateGeometricState(0f, true);
                    lod[count].updateModelBound();
                    lod[count].updateWorldBound();
                    if (count == 3) {
                        lod[count].setLocalScale(new Vector3f(1.0f, 0.9f, 1.0f));
                    }
                } catch (MalformedURLException e) {
                    logger.debug(e);
                } catch (IOException e) {
                    logger.debug(e);
                }
            }
        }
        switchNode = new SwitchNode("switchnode");
        switchNode.attachChildAt(new SharedNode("sharedRack0", lod[0]), 0);
        switchNode.attachChildAt(new SharedNode("sharedRack1", lod[1]), 1);
        switchNode.attachChildAt(new SharedNode("sharedRack2", lod[2]), 2);
        switchNode.attachChildAt(new SharedNode("sharedRack2", lod[2]), 3);
        switchNode.setActiveChild(0);
        switchNode.setLocalTranslation(new Vector3f(0, 3.7f, 0));
        node.attachChild(switchNode);
        products = new ArrayList<VisualEntity>(capacity);
        setNode(mainNode);
        getNode().updateGeometricState(0f, true);
        getNode().updateModelBound();

        Node _node = new Node("hiliter");
        Box box = new Box("hiliter", ((BoundingBox) getNode().getWorldBound()).getCenter().clone()
                .subtractLocal(getNode().getLocalTranslation()), 4f, 4f, 4f);
        box.setModelBound(new BoundingBox());
        box.updateModelBound();
        _node.attachChild(box);
        _node.setModelBound(new BoundingBox());
        _node.updateModelBound();
        _node.setCullHint(CullHint.Always);
        getNode().attachChild(_node);
    }

    private Vector3f calcPos(int count) {
        Vector3f ret = new Vector3f();
        float r = 2.4f;
        float alpha = count * 30;
        float mult = 1;
        if (alpha > 180) {
            alpha -= 180;
            mult = -1;
        }
        ret.y = 5.3f;
        ret.z = mult * (float) (r * Math.cos(alpha * Math.PI / 180));
        ret.x = mult * (float) Math.sqrt(r * r - ret.z * ret.z);
        return ret;
    }

    private Quaternion calcRot(int count) {
        float rad = 0;
        if (count <= 6) {
            rad = 90 + count * 30;
        } else {
            rad = 90 + count * 30;
        }
        Quaternion quat = new Quaternion(new float[] { 0, (float) (rad * Math.PI / 180), 0 });
        return quat;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.Entity#loaded()
     */
    @Override
    public void loaded() {
        prepare();
        for (RifidiTag tag : getTags()) {
            RifidiTagWithParent r = new RifidiTagWithParent();
            r.parent = this;
            r.tag = tag;
            wrappers.add(r);
        }
        List<RifidiTag> stackTags = new ArrayList<RifidiTag>(tags);
        for (VisualEntity prod : products) {
            stackTags.remove(((Clothing) prod).getRifidiTag());
        }
        tagStack.addAll(stackTags);
    }

    private void prepare() {
        if (clotModel == null) {
            try {
                URI modelpath = getClass().getClassLoader()
                        .getResource("org/rifidi/designer/library/retail/clothing/cloth0.jme").toURI();
                clotModel = (Node) BinaryImporter.getInstance().load(modelpath.toURL());
            } catch (MalformedURLException e) {
                logger.error("Can't load model: " + e);
            } catch (IOException e) {
                logger.error("Can't load model: " + e);
            } catch (URISyntaxException e) {
                logger.error("Can't load model: " + e);
            }
            Quaternion quat = new Quaternion(new float[] { (float) Math.toRadians(270f), 0f, 0f });
            clotModel.setLocalRotation(quat);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.interfaces.IContainer#addVisualEntity
     * (org.rifidi.designer.entities.VisualEntity)
     */
    @Override
    public void addVisualEntity(final VisualEntity visualEntity) {
        if (accepts(visualEntity) && !isFull() && products.contains(visualEntity)) {
            List<Entity> del = new ArrayList<Entity>();
            del.add(visualEntity);
            entitiesService.deleteEntities(del);
            addClothing();
            tagStack.push(((Clothing) visualEntity).getRifidiTag());
            return;
        }
        throw new RuntimeException("Stupid!! Wrong type or full: " + accepts(visualEntity) + " " + isFull());
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.interfaces.IContainer#getVisualEntity
     * ()
     */
    @Override
    public VisualEntity getVisualEntity() {
        try {
            removeClothing();
            RifidiTag tag = tagStack.pop();
            Clothing clothing = new Clothing();
            clothing.setRifidiTag(tag);
            clothing.setName(clothing.getName() + " " + tag);
            clothing.setStartTranslation(getNode().getWorldTranslation().clone());
            clothing.setStartRotation(getNode().getLocalRotation().clone());
            clothing.setProducer(this);
            entitiesService.addEntity(clothing, null, null);
            products.add(clothing);
            return clothing;
        } catch (EmptyStackException e) {
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.interfaces.IContainer#getVisualEntity
     * (org.rifidi.designer.entities.VisualEntity)
     */
    @Override
    public VisualEntity getVisualEntity(VisualEntity visualEntity) {
        logger.debug("direct selection not supported");
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.designer.entities.interfaces.IContainer#getVisualEntitySet ()
     */
    @Override
    public List<VisualEntity> getVisualEntityList() {
        return Collections.unmodifiableList(products);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.interfaces.IContainer#isFull()
     */
    @Override
    public boolean isFull() {
        return capacity <= itemCount;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.interfaces.IContainer#accepts(org
     * .rifidi.designer.entities.VisualEntity)
     */
    @Override
    public boolean accepts(VisualEntity visualEntity) {
        return visualEntity instanceof Clothing;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.VisualEntity#setLOD(int)
     */
    @Override
    public void setLOD(int lod) {
        if (switchNode != null) {
            switchNode.setActiveChild(lod);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.VisualEntity#getBoundingNode()
     */
    @Override
    public Node getBoundingNode() {
        return (Node) getNode().getChild("hiliter");
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.services.tags.model.IRifidiTagContainer#addTags(java.util.
     * Collection)
     */
    @Override
    public void addTags(Collection<RifidiTag> tags) {
        for (RifidiTag tag : tags) {
            if (this.tags.size() < capacity) {
                try {
                    tagService.takeRifidiTag(tag, this);
                    tag.addPropertyChangeListener(this);
                    RifidiTagWithParent r = new RifidiTagWithParent();
                    r.parent = this;
                    r.tag = tag;
                    addClothing();
                    wrappers.add(r);
                    this.tags.add(tag);
                    tagStack.push(tag);
                } catch (RifidiTagNotAvailableException e) {
                    logger.error("Tag not available: " + e);
                }
            }
        }
    }

    private void addClothing() {
        update(new Callable<Object>() {

            /*
             * (non-Javadoc)
             * 
             * @see java.util.concurrent.Callable#call()
             */
            @Override
            public Object call() throws Exception {
                // TODO: Possible race condition
                Node clothing = new Node("cloth " + itemCount++);
                SharedNode shared = new SharedNode(clotModel);
                clothing.attachChild(shared);
                Position pos = new Position(calcPos(itemCount), calcRot(itemCount));
                clothing.getLocalTranslation().addLocal((Vector3f) pos.translation.clone());
                clothing.getLocalRotation().set(new Quaternion(pos.rotation));
                getNode().attachChild(clothing);
                clothing.updateRenderState();
                return null;
            }

        });
    }

    private void removeClothing() {
        update(new Callable<Object>() {

            /*
             * (non-Javadoc)
             * 
             * @see java.util.concurrent.Callable#call()
             */
            @Override
            public Object call() throws Exception {
                itemCount--;
                getNode().getChild("cloth " + itemCount).removeFromParent();
                return null;
            }

        });
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.services.tags.model.IRifidiTagContainer#removeTags(java.util
     * .Collection)
     */
    @Override
    public void removeTags(Collection<RifidiTag> tags) {
        // only remove tags that are currently available.
        if (this.tagStack.containsAll(tags)) {
            tagStack.removeAll(tags);
            this.tags.removeAll(tags);
            Set<RifidiTagWithParent> rem = new HashSet<RifidiTagWithParent>();
            for (Object wrapper : wrappers) {
                if (tags.contains(((RifidiTagWithParent) wrapper).tag)) {
                    ((RifidiTagWithParent) wrapper).tag.removePropertyChangeListener(this);
                    rem.add((RifidiTagWithParent) wrapper);
                }
            }
            wrappers.removeAll(rem);
            tagService.releaseRifidiTags(tags, this);
        }
    }

    /**
     * @return the wrappers
     */
    public WritableList getWrappers() {
        return this.wrappers;
    }

    /**
     * Get a string representation of the tags this producer owns.
     * 
     * @return
     */
    public String getTagList() {
        StringBuffer buf = new StringBuffer();
        for (RifidiTag tag : tags) {
            buf.append(tag + "\n");
        }
        return buf.toString();
    }

    @Property(displayName = "Tags", description = "tags assigned to this rack", readonly = true, unit = "")
    public void setTagList(String tagList) {

    }

    /*
     * (non-Javadoc)
     * 
     * @seejava.beans.PropertyChangeListener#propertyChange(java.beans.
     * PropertyChangeEvent)
     */
    @Override
    public void propertyChange(PropertyChangeEvent arg0) {

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.services.tags.model.IRifidiTagContainer#getTags()
     */
    @Override
    public Collection<RifidiTag> getTags() {
        return tags;
    }

    /**
     * @param tagService
     *            the tagService to set
     */
    @Inject
    public void setTagService(IRifidiTagService tagService) {
        this.tagService = tagService;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.designer.entities.interfaces.IProducer#getProducts()
     */
    @Override
    public List<Clothing> getProducts() {
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.designer.entities.interfaces.IProducer#productDestroied(org
     * .rifidi.designer.entities.interfaces.IProduct)
     */
    @Override
    public void productDestroied(Clothing product) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.designer.entities.interfaces.IProducer#setProducts(java.util
     * .List)
     */
    @Override
    public void setProducts(List<Clothing> entities) {
    }

    /**
     * @param entitiesService
     *            the entitiesService to set
     */
    @Inject
    public void setEntitiesService(EntitiesService entitiesService) {
        this.entitiesService = entitiesService;
    }

}