1 (function(global){	// BEGIN CLOSURE
  2 
  3 var Joint = global.Joint;
  4 
  5 Joint.Mixin(Joint.prototype, /** @lends Joint.prototype */ {
  6     /**
  7      * Returns compact object representation of joint. Used for serialization.
  8      * @return {Object} Compact representation of the joint.
  9      */
 10     compact: function(){
 11 	var start = this.startObject(), end = this.endObject(),
 12 	    regs = this._registeredObjects, iRegs = regs.length, reg,
 13 	    j = {
 14 		object: "joint",
 15 		euid: this.euid(),
 16 		opt: this._opt,
 17 		from: undefined,
 18 		to: undefined,
 19 		registered: {
 20 		    start: [],
 21 		    end: [],
 22 		    both: []
 23 		}
 24 	    };
 25 	// @todo Ugly!!! Joint shouldn't know anything about Joint.dia! Remove!
 26 
 27 	// from/to
 28 	if (start.wholeShape)
 29 	    j.from = start.wholeShape.euid();
 30 	if (end.wholeShape)
 31 	    j.to = end.wholeShape.euid();
 32 
 33 	if (this.isStartDummy())
 34 	    j.from = start.attrs.cx + "@" + start.attrs.cy;
 35 	if (this.isEndDummy())
 36 	    j.to = end.attrs.cx + "@" + end.attrs.cy;
 37 
 38 	// registered objects processing
 39 	while(iRegs--){
 40 	    reg = regs[iRegs];
 41 	    j.registered[reg._capToStick || "both"].push(reg.euid());
 42 	}
 43 	return j;
 44     },
 45     /**
 46      * @return {String} JSON representation of joint.
 47      */
 48     stringify: function(){
 49 	return JSON.stringify(this.compact());
 50     }
 51 });
 52 
 53 Joint.Mixin(Joint.dia, /** @lends Joint.dia */ {
 54      /**
 55       * Clones diagram in the current paper.
 56       * @return {Array} Array of the constructed elements.
 57       */
 58     clone: function(){
 59 	return this.parse(this.stringify(Joint.paper()));
 60     },
 61     /**
 62      * Construct a diagram from the JSON representation.
 63      * @param {String} JSON
 64      * @return {Array} Array of the constructed elements.
 65      */
 66     parse: function(json){
 67 	var arr = JSON.parse(json), o, m, e,
 68 	    element, joints = [], i, len, elements = {},
 69 	    objects = [];
 70 
 71 	if (!(arr instanceof Array)) arr = [arr];
 72 
 73 	// for all elements
 74 	for (i = 0, len = arr.length; i < len; i++){
 75 	    o = arr[i];
 76 
 77 	    m = o.module;
 78 	    e = o.object;
 79 
 80 	    // create joints separatly, after all elements are created
 81 	    // so that they can connect them
 82 	    if (e === "joint"){
 83 		joints.push(o);
 84 		objects.push(o);
 85 		continue;
 86 	    }
 87 	    // construct the element
 88 	    if (this[m]){
 89 		if (this[m][e]){
 90 		    element = this[m][e].create(o);
 91 		} else {
 92 		    console.error("Object " + e + " of module " + m + " is missing.");
 93 		    return;
 94 		}
 95 	    } else {
 96 		console.error("Module " + m + " is missing.");
 97 		return;
 98 	    }
 99 	    if (o.euid) elements[o.euid] = element;
100 
101 	    // translate, @todo rotate, scale
102 	    element.translate(o.dx, o.dy);
103 	    // element.rotate(o.rot);
104 	    element.scale(o.sx, o.sy);
105 	    objects.push(element);
106 	}
107 	this.hierarchize(elements);
108 	this.createJoints(joints, elements);
109 	return objects;
110     },
111     /**
112      * @private
113      */
114     hierarchize: function(elements){
115 	var euid, element;
116 	for (euid in elements){
117 	    if (!elements.hasOwnProperty(euid)) continue;
118 	    element = elements[euid];
119 	    if (element.properties.parent && elements[element.properties.parent])
120 		elements[element.properties.parent].addInner(element);
121 	}
122     },
123     /**
124      * Create joints.
125      * @private
126      * @param {Array} joints Matrix of joints for each element.
127      * @param {Object} elements Hash table of elements (key: euid, value: element).
128      */
129     createJoints: function(joints, elements){
130 	var iJoints = joints.length,
131             joint, from, to, realFrom, realTo,
132             newJoint, toRegister, toRegisterElement, iRegister, cap,
133 	    sides = ["start", "end", "both"], iSides = sides.length;
134 	// for all joints of all elements
135 	while (iJoints--){
136 	    joint = joints[iJoints];
137 	    from = elements[joint.from];
138 	    to = elements[joint.to];
139 
140 	    // point or element wrapper
141 	    realFrom = (from) ? from.wrapper : {x: joint.from.split("@")[0], y: joint.from.split("@")[1]};
142 	    realTo = (to) ? to.wrapper : {x: joint.to.split("@")[0], y: joint.to.split("@")[1]};
143 
144 	    // create joint
145 	    newJoint = this.Joint(realFrom, realTo, joint.opt);
146 	    // register caps - elements
147 	    toRegister = [];
148 	    iSides = sides.length;
149 	    while (iSides--){
150 		cap = sides[iSides];
151 		iRegister = joint.registered[cap].length;
152 		while (iRegister--){
153 		    if (elements[joint.registered[cap][iRegister]]){
154 			toRegisterElement = elements[joint.registered[cap][iRegister]];
155 			toRegisterElement._capToStick = cap;
156 			toRegister.push(toRegisterElement);
157 		    }
158 		}
159 	    }
160 	    newJoint.registerForever(toRegister);
161 	}//endwhile (iJoints--)
162     },
163     /**
164      * Stringify the whole diagram (occupying a paper).
165      * @param {RaphaelPaper} paper Raphael paper the diagram belongs to.
166      * @return {String} JSON representation of the diagram.
167      */
168     stringify: function(paper){
169 	var objs, iObjs, o, str = [],
170             registeredObjects = this._registeredObjects, registeredJoints = this._registeredJoints,
171             paperEuid = paper.euid();
172 	// elements
173 	if (registeredObjects[paperEuid]){
174 	    objs = registeredObjects[paperEuid];
175 	    iObjs = objs.length;
176 	    while (iObjs--){
177 		o = objs[iObjs];
178 		if (o.object)
179 		    str.push(o.stringify());
180 	    }
181 	}
182 	// joints
183 	if (registeredJoints[paperEuid]){
184 	    objs = registeredJoints[paperEuid];
185 	    iObjs = objs.length;
186 	    while (iObjs--){
187 		o = objs[iObjs];
188 		str.push(o.stringify());
189 	    }
190 	}
191 	return "[" + str.join(",") + "]";
192     }
193 });
194 
195 Joint.Mixin(Joint.dia.Element.prototype, /** @lends Joint.dia.Element.prototype */ {
196     /**
197      * @return JSON representation of the element.
198      */
199     stringify: function(){
200 	return JSON.stringify(Joint.Mixin(this.properties, { euid: this.euid() }));
201     },
202     /**
203      * Clone element.
204      * @return {Element} Cloned element.
205      */
206     clone: function(){
207 	return Joint.dia.parse(this.stringify())[0];
208     }
209 });
210 
211 })(this);	// END CLOSURE
212