1 (function(global){	// BEGIN CLOSURE
  2 
  3 var Joint = global.Joint,
  4      Element = Joint.dia.Element;
  5 
  6 /**
  7  * @name Joint.dia.devs
  8  * @namespace Holds functionality related to Discrete EVent System (DEVS) diagrams.
  9  */
 10 var devs = Joint.dia.devs = {};
 11 
 12 /**
 13  * Predefined arrow.
 14  * @name Joint.dia.devs.arrow
 15  * @memberOf Joint.dia.devs
 16  * @example a1.port("o", "out1").joint(c1.port("i", "in"), Joint.dia.devs.arrow);
 17  */
 18 devs.arrow = {
 19   endArrow: { type: "none" },
 20   startArrow: {type: "none"},
 21   attrs: { "stroke-dasharray": "none" }
 22 };
 23 
 24 /**
 25  * DEVS atomic/coupled model.
 26  * @name Model.create
 27  * @methodOf Joint.dia.devs
 28  * @param {Object} properties
 29  * @param {Object} properties.rect Bounding box of the model (e.g. {x: 50, y: 100, width: 150, height: 100}).
 30  * @param {String} [properties.label] The name of the model.
 31  * @param {Number} [properties.labelOffsetX] Offset in x-axis of the label from the model rectangle origin.
 32  * @param {Number} [properties.labelOffsetY] Offset in y-axis of the label from the model rectangle origin.
 33  * @param {Number} [properties.portsOffsetX] Offset in x-axis of the ports from the model rectangle origin.
 34  * @param {Number} [properties.portsOffsetY] Offset in y-axis of the ports from the model rectangle origin.
 35  * @param {Number} [properties.iPortRadius] Radius of the input ports circle.
 36  * @param {Number} [properties.oPortRadius] Radius of the output ports circle.
 37  * @param {Object} [properties.iPortAttrs] SVG attributes of the appearance of the input ports.
 38  * @param {Object} [properties.oPortAttrs] SVG attributes of the appearance of the output ports.
 39  * @param {Number} [properties.iPortLabelOffsetX] Offset in x-axis of the input ports label.
 40  * @param {Number} [properties.oPortLabelOffsetX] Offset in x-axis of the output ports label.
 41  * @param {array} [properties.iPorts] The input port names.
 42  * @param {array} [properties.oPorts] The output port names.
 43  * @param {Object} [properties.attrs] SVG attributes of the appearance of the model.
 44  * @example
 45 var a1 = Joint.dia.devs.Model.create({
 46   rect: {x: 30, y: 90, width: 100, height: 60},
 47   label: "Atomic 1",
 48   attrs: {
 49     fill: "90-#000-#f00:1-#fff"
 50   },
 51   iPorts: ["in1"],
 52   oPorts: ["out1", "out2"]
 53 });
 54  */
 55 devs.Model = Element.extend({
 56      object: "Model",
 57      module: "devs",
 58      init: function(properties){
 59 	 // options
 60 	 var p = Joint.DeepSupplement(this.properties, properties, {
 61              labelOffsetX: 20,
 62              labelOffsetY: 5,
 63              portsOffsetX: 5,
 64              portsOffsetY: 20,
 65              iPortRadius: 5,
 66              oPortRadius: 5,
 67              iPortAttrs: { fill: 'green', stroke: 'black' },
 68              oPortAttrs: { fill: 'red', stroke: 'black' },
 69              iPortLabelOffsetX: -10,
 70              iPortLabelOffsetY: -10,
 71              oPortLabelOffsetX: 10,
 72              oPortLabelOffsetY: -10,
 73              iPorts: [],
 74              oPorts: []
 75          });
 76 	 // wrapper
 77 	 var paper = this.paper, i;
 78 	 this.setWrapper(paper.rect(p.rect.x, p.rect.y, p.rect.width, p.rect.height).attr(p.attrs));
 79 	 // inner
 80 	 this.addInner(this.getLabelElement());	// label
 81 	 // draw ports
 82 	 for (i = 0, l = p.iPorts.length; i < l; i++){
 83 	     this.addInner(this.getPortElement("i", i + 1, p.iPorts[i]));
 84 	 }
 85 	 for (i = 0, l = p.oPorts.length; i < l; i++){
 86 	     this.addInner(this.getPortElement("o", i + 1, p.oPorts[i]));
 87 	 }
 88 	 // delete all ports related properties, they are saved in port objects
 89 	 p.iPorts = p.oPorts = p.portsOffsetX = p.portsOffsetY = p.iPortRadius = p.oPortRadius = p.iPortAttrs = p.oPortAttrs = p.iPortLabelOffsetX = p.iPortLabelOffsetY = p.oPortLabelOffsetX = p.oPortLabelOffsetY = undefined;
 90      },
 91      getLabelElement: function(){
 92 	 var p = this.properties,
 93 	     bb = this.wrapper.getBBox(),
 94 	     t = this.paper.text(bb.x, bb.y, p.label).attr(p.labelAttrs || {}),
 95 	     tbb = t.getBBox();
 96 	 t.translate(bb.x - tbb.x + p.labelOffsetX, bb.y - tbb.y + p.labelOffsetY);
 97 	 return t;
 98      },
 99      getPortElement: function(type, index, label){
100 	 var bb = this.wrapper.getBBox(), p = this.properties,
101 	     port = devs.Port.create({
102 	         label: label,
103     	         type: type,
104 	         position: {x: bb.x + ((type === "o") ? bb.width : 0), y: bb.y + p.portsOffsetY * index},
105 	         radius: p[type + "PortRadius"],
106 	         attrs: p[type + "PortAttrs"],
107 	         offsetX: p[type + "PortLabelOffsetX"],
108 	         offsetY: p[type + "PortLabelOffsetY"]
109              });
110 	 return port;
111      },
112      /**
113       * Get a port object. It can be used further for connecting other port objects.
114       * @param {String} type "i"|"o"
115       * @param {String} label Name of the port.
116       * @return {Port}
117       */
118      port: function(type, label){
119 	 var el;
120 	 for (var i = 0, l = this.inner.length; i < l; i++){
121 	     el = this.inner[i];
122 	     if (el.properties && label == el.properties.label && type == el.properties.type){
123 		 return el;
124 	     }
125 	 }
126 	 return undefined;
127      },
128      joint: function(oPort, to, iPort, opt){
129 	 // shorthand
130 	 if (!to.port) return undefined;	// non-DEVS object
131 	 return this.port("o", oPort).joint(to.port("i", iPort), opt);
132      },
133      zoom: function(){
134 	 // @todo
135      }				
136 });
137 
138 devs.Port = Element.extend({
139      object: "Port",
140      module: "devs",
141      // doesn't have object and module properties => it's invisible for serializer
142      init: function(properties){
143 	 var p = Joint.DeepSupplement(this.properties, properties, {
144              label: '',
145              offsetX: 0,
146              offsetY: 0,
147              type: 'i'
148          });
149 	 this.setWrapper(this.paper.circle(p.position.x, p.position.y, p.radius).attr(p.attrs));
150 	 this.addInner(this.getLabelElement());
151      },
152      getLabelElement: function(){
153 	 var bb = this.wrapper.getBBox(), p = this.properties,
154 	     t = this.paper.text(bb.x, bb.y, p.label),
155 	     tbb = t.getBBox();
156 	 t.translate(bb.x - tbb.x + p.offsetX, bb.y - tbb.y + p.offsetY);
157 	 return t;
158      },
159      zoom: function(){
160 	 // @todo
161      }
162 });
163 
164 })(this);	// END CLOSURE
165