Merge branch 'master' of github.com:systemed/potlatch2
[potlatch2.git] / net / systemeD / halcyon / connection / actions / SplitWayAction.as
1 package net.systemeD.halcyon.connection.actions {
2
3     import net.systemeD.halcyon.connection.*;
4     
5     public class SplitWayAction extends CompositeUndoableAction {
6     
7         private var selectedWay:Way;
8         private var nodeIndex:uint; // Index rather than node required as nodes can occur multiple times
9         private var newWay:Way;
10     
11         public function SplitWayAction(selectedWay:Way, nodeIndex:uint) {
12             super("Split way "+selectedWay.id);
13             this.selectedWay = selectedWay;
14             this.nodeIndex = nodeIndex;
15         }
16     
17         public override function doAction():uint {
18             if (newWay==null) {
19                                 newWay = selectedWay.connection.createWay(
20                                         selectedWay.getTagsCopy(), 
21                                         selectedWay.sliceNodes(nodeIndex,selectedWay.length),
22                                         push);
23
24                                 // we reverse the list, which is already sorted by position. This way positions aren't affected
25                                 // for previous inserts when all the inserts are eventually executed
26                                 for each (var o:Object in selectedWay.memberships.reverse()) {
27                                         // don't add a turn restriction to the relation if it's no longer relevant
28                                         if (o.relation.tagIs('type','restriction')) {
29                                                 var vias:Array=o.relation.findMembersByRole('via');
30                                                 if (vias.length && vias[0] is Node) {
31                                                         if (newWay.indexOfNode(Node(vias[0]))==-1) { 
32                                                                 continue;
33                                                         }
34                                                 }
35                                         }
36
37                   // newWay should be added immediately after the selectedWay, unless the setup
38                   // is arse-backwards. By that I mean either:
39                   // a) The first node (0) of selectedWay is in the subsequentWay, or
40                   // b) The last node (N) of selectedWay is in the preceedingWay
41                   // Note that the code above means newWay is the tail of selectedWay S-->.-->N
42                   // i.e. preceedingWay x--x--x--x                             P-1   ↓
43                   //      selectedWay            N<--.<--S<--.<--0             P     ↓ relation members list
44                   //      subsequentWay                           x--x--x--x   P+1   ↓
45                   // There are some edge cases:
46                   // 1) If the immediately adjacent member isn't a way - handled fine
47                   // 2) If the selectedWay shares first/last node with non-adjacent ways - phooey
48                   
49                   var backwards:Boolean = false;
50                   // note that backwards is actually a ternary of 'true', 'false', and 'itdoesntmatter' (== 'false')
51                   
52                   var offset:int = 1; //work from o.position outwards along the length of the relationmembers
53                   while ((o.position - offset) >= 0 || (o.position + offset < o.relation.length)) {
54                     if ((o.position - offset >= 0) && o.relation.getMember(o.position - offset).entity is Way)  {
55                       var preceedingWay:Way = o.relation.getMember(o.position - offset).entity as Way;
56                       if(preceedingWay.indexOfNode(selectedWay.getLastNode()) >= 0) {
57                         backwards = true;
58                       }
59                     }
60                     if ((o.position + offset < o.relation.length) && o.relation.getMember(o.position + offset).entity is Way) {
61                       var subsequentWay:Way = o.relation.getMember(o.position + offset).entity as Way;
62                       if(subsequentWay.indexOfNode(selectedWay.getNode(0)) >= 0) {
63                         backwards = true;
64                       }
65                     }
66                     offset++;
67                   }
68                   if (backwards) {
69                     o.relation.insertMember(o.position, new RelationMember(newWay, o.role), push); //insert newWay before selectedWay
70                   } else {
71                     o.relation.insertMember(o.position + 1, new RelationMember(newWay, o.role), push); // insert after
72                   }
73                 }
74                 
75                 // now that we're done with the selectedWay, remove the nodes
76                 selectedWay.deleteNodesFrom(nodeIndex+1, push);
77
78                                 // and remove from any turn restrictions that aren't relevant
79                                 for each (var r:Relation in selectedWay.findParentRelationsOfType('restriction')) {
80                                         vias=r.findMembersByRole('via');
81                                         if (vias.length && vias[0] is Node) {
82                                                 if (selectedWay.indexOfNode(Node(vias[0]))==-1) { 
83                                                         r.removeMember(selectedWay,push);
84                                                 }
85                                         }
86                                 }
87
88             }
89             newWay.suspend();
90             selectedWay.suspend();
91             super.doAction();
92             newWay.resume();
93             selectedWay.resume();
94             return SUCCESS;
95         }
96         
97         public override function undoAction():uint {
98             selectedWay.suspend();
99             newWay.suspend();
100             
101             super.undoAction();
102             
103             newWay.resume();
104             selectedWay.resume();
105             return SUCCESS;
106         }
107     }
108
109 }