File Coverage

blib/lib/VoiceXML/Client/Document.pm
Criterion Covered Total %
statement 153 184 83.1
branch 37 66 56.0
condition 21 45 46.6
subroutine 20 24 83.3
pod 3 20 15.0
total 234 339 69.0


line stmt bran cond sub pod time code
1             package VoiceXML::Client::Document;
2              
3              
4              
5 3     3   16 use strict;
  3         8  
  3         107  
6              
7 3     3   16 use Data::Dumper;
  3         6  
  3         255  
8 3     3   16 use base qw(VoiceXML::Client::Item);
  3         6  
  3         247  
9              
10              
11 3         6848 use vars qw{
12             $VERSION
13 3     3   17 };
  3         6  
14              
15             $VERSION = $VoiceXML::Client::Item::VERSION;
16              
17              
18             =head1 COPYRIGHT AND LICENSE
19              
20            
21             Copyright (C) 2007,2008 by Pat Deegan.
22             All rights reserved
23             http://voicexml.psychogenic.com
24              
25             This library is released under the terms of the GNU GPL version 3, making it available only for
26             free programs ("free" here being used in the sense of the GPL, see http://www.gnu.org for more details).
27             Anyone wishing to use this library within a proprietary or otherwise non-GPLed program MUST contact psychogenic.com to
28             acquire a distinct license for their application. This approach encourages the use of free software
29             while allowing for proprietary solutions that support further development.
30              
31              
32             This file is part of VoiceXML::Client.
33              
34            
35            
36             VoiceXML::Client is free software: you can redistribute it and/or modify
37             it under the terms of the GNU General Public License as published by
38             the Free Software Foundation, either version 3 of the License, or
39             (at your option) any later version.
40              
41             VoiceXML::Client is distributed in the hope that it will be useful,
42             but WITHOUT ANY WARRANTY; without even the implied warranty of
43             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44             GNU General Public License for more details.
45              
46             You should have received a copy of the GNU General Public License
47             along with VoiceXML::Client. If not, see .
48              
49              
50             =cut
51              
52              
53             =head2 new
54              
55             =cut
56             sub new {
57 3     3 1 10 my $class = shift;
58 3         9 my $docname = shift;
59 3         16 my $runtime = shift;
60            
61            
62            
63 3         9 my $self = {};
64            
65 3   33     23 bless $self, ref $class || $class;
66            
67            
68 3   33     42 $self->{'type'} = ref $class || $class;
69 3         10 $self->{'_runtime'} = $runtime;
70 3         38 $self->{'_context'} = $runtime->create_context();
71 3         10 $self->{'docname'} = $docname;
72            
73 3         9 $self->{'forms'} = [];
74 3         9 $self->{'formindices'} = {};
75            
76 3         8 $self->{'variables'} = {};
77            
78 3         9 $self->{'nextform'} = 0;
79 3         9 $self->{'nextdocument'} = 0;
80 3         8 $self->{'currentitem'} = 0;
81            
82            
83 3         17 return $self;
84             }
85              
86             sub init {
87 0     0 1 0 my $self = shift;
88            
89 0         0 $self->{'items'} = [];
90            
91 0         0 return 1;
92             }
93              
94              
95             =head2 addItem ITEM
96              
97             Appends ITEM to the list of items for the document. Items may be any VXML::Item::XXX subclass, while
98             ITEM itself may be a single ITEM object reference or an ARRAY ref of VXML::Item::XXX objects (each will
99             be appended in order).
100              
101             Returns the number of appended items.
102              
103             =cut
104              
105             sub addItem {
106 15     15 1 19 my $self = shift;
107 15         17 my $item = shift;
108            
109            
110 15         26 my $count = 0;
111 15 100       37 if (ref $item eq 'ARRAY')
112             {
113 3         6 foreach my $singleItem (@{$item})
  3         10  
114             {
115 12         34 $count += $self->addItem($singleItem);
116             }
117             } else {
118            
119 12         15 push @{$self->{'items'}}, $item;
  12         24  
120 12         15 $count = 1;
121             }
122            
123 15         34 return $count;
124            
125             }
126              
127             sub nextFormId {
128 4     4 0 6 my $self = shift;
129 4         7 my $setTo = shift; # optional
130            
131 4 100 66     20 if (defined $setTo && exists $self->{'formindices'}->{$setTo})
132             {
133 2         18 $self->{'nextform'} = $setTo;
134 2         8 my $nextFormIdx = $self->getFormItemsIndex($setTo);
135            
136 2         6 $self->{'currentitem'} = $nextFormIdx;
137 2         12 $self->{'items'}->[$nextFormIdx]->reset();
138            
139 2         4 return $setTo;
140            
141             }
142            
143 2         4 my $idx = 0;
144 2 50       15 if ($self->{'nextform'})
145             {
146 2         4 my $nextFormName = $self->{'nextform'};
147            
148 2 50 33     25 if (exists $self->{'formindices'}->{$nextFormName}
149             && ( exists $self->{'forms'}->[$self->{'formindices'}->{$nextFormName}] )
150             )
151             {
152 2         5 $idx = $self->{'formindices'}->{$nextFormName};
153 2         8 $self->{'variables'}->{$self->{'forms'}->[$idx]->{'guard'}} = undef;
154             }
155             }
156            
157 2         6 for (my $i = $idx; $i < scalar @{$self->{'forms'}}; $i++)
  2         8  
158             {
159            
160 2 50       11 if ($self->{'variables'}->{$self->{'forms'}->[$i]->{'guard'}})
161             {
162 0 0       0 VoiceXML::Client::Util::log_msg("nextFormId() Skipping form " . $self->{'forms'}->[$i]->{'name'}
163             . ' because guard condition is set') if ($VoiceXML::Client::Debug > 1);
164             } else {
165 2 50       7 VoiceXML::Client::Util::log_msg("nextFormId() returning form id " . $self->{'forms'}->[$i]->{'name'} )
166             if ($VoiceXML::Client::Debug);
167 2         13 return $self->{'forms'}->[$i]->{'name'} ;
168             }
169             }
170            
171 0         0 return undef;
172             }
173              
174             sub getForm {
175 3     3 0 6 my $self = shift;
176 3         5 my $id = shift ;
177            
178 3         8 my $idx = $self->getFormItemsIndex($id);
179            
180            
181 3 50       10 return undef unless (defined $idx);
182              
183 3         11 return $self->{'items'}->[$idx];
184            
185             }
186              
187             sub getFormItemsIndex {
188 5     5 0 9 my $self = shift;
189 5         6 my $id = shift ;
190            
191 5 50       14 return undef unless defined ($id);
192              
193 5         8 for (my $i=0; $i < scalar @{$self->{'items'}}; $i++)
  24         60  
194             {
195 24         35 my $itm = $self->{'items'}->[$i];
196            
197 24 100 100     110 if ($itm->{'type'} eq 'VoiceXML::Client::Item::Form'
198             && $itm->{'id'} eq $id)
199             {
200 5 50       34 VoiceXML::Client::Util::log_msg("Found form $id att idx $i")
201             if ($VoiceXML::Client::Debug > 1);
202            
203 5         12 return $i ;
204             }
205            
206             }
207            
208 0         0 return undef;
209             }
210            
211              
212              
213             sub getNextForm {
214 2     2 0 4 my $self = shift;
215            
216 2         6 my $id = $self->nextFormId();
217            
218            
219 2         8 return $self->getForm($id);
220            
221             }
222              
223             sub getNextItem {
224 14     14 0 18 my $self = shift;
225            
226 14 100       43 return $self->getNextForm() if ($self->{'nextform'});
227            
228            
229 12   100     44 $self->{'currentitem'} ||= 0;
230            
231 12         17 my $oldChildSetting = $self->{'currentitem'} ;
232 12         16 my $i = $oldChildSetting;
233 12         17 while ($i < scalar @{$self->{'items'}})
  13         43  
234             {
235            
236 9         17 $self->{'currentitem'} = $i;
237            
238 9         79 my $cType = $self->{'items'}->[$i]->getType();
239 9 100       28 if ($cType ne 'VoiceXML::Client::Item::Form')
240             {
241             # not a form, just return it in sequence
242 5         18 return $self->{'items'}->[$i];
243            
244             } else
245             {
246             # it IS a form... handle guard vars...
247 4         22 my $formName = $self->{'items'}->[$i]->id();
248            
249 4 50       18 if (exists $self->{'formindices'}->{$formName})
250             {
251 4         15 my $formIdx = $self->{'formindices'}->{$formName};
252            
253 4 100       33 if (! $self->{'variables'}->{$self->{'forms'}->[$formIdx]->{'guard'}})
254             {
255             # not visited yet... go for it.
256 3         16 return $self->{'items'}->[$i];
257             }
258             }
259             }
260            
261            
262 1         2 $i++;
263            
264             }
265            
266 4         9 $self->{'currentitem'} = $oldChildSetting;
267            
268 4         9 return undef;
269             }
270              
271             sub currentItemPosition {
272 0     0 0 0 my $self = shift;
273 0         0 my $setTo = shift; # optional
274            
275 0 0 0     0 if (defined $setTo && $setTo =~ m/^\d+$/ && $setTo < scalar @{$self->{'items'}})
  0   0     0  
276             {
277 0         0 $self->{'currentitem'} = $setTo;
278             }
279            
280 0         0 return $self->{'currentitem'};
281             }
282              
283             sub proceedToNextItem {
284 9     9 0 13 my $self = shift;
285            
286 9         19 return $self->{'currentitem'}++;
287            
288             }
289              
290              
291             sub registerForm {
292 7     7 0 12 my $self = shift;
293 7         12 my $formName = shift;
294 7         10 my $guard = shift;
295            
296 7         12 push @{$self->{'forms'}}, {
  7         27  
297             'name' => $formName,
298             'guard' => $guard};
299            
300 7         19 $self->{'formindices'}->{$formName} = $#{$self->{'forms'}};
  7         25  
301            
302            
303 7         20 $self->registerVariable($formName);
304             }
305              
306             sub registerVariable {
307 37     37 0 48 my $self = shift;
308 37   50     99 my $varName = shift || return;
309 37         55 my $val = shift;
310            
311 37 50       77 if (defined $val)
312             {
313 0         0 $self->{'variables'}->{$varName} = $val;
314             } else {
315            
316 37         188 $self->{'variables'}->{$varName} = undef;
317             }
318            
319             }
320              
321             sub globalVar {
322 17     17 0 31 my $self = shift;
323 17   50     49 my $varName = shift || return;
324 17         24 my $val = shift; #optional
325            
326            
327 17 100       49 if (defined $val)
328             {
329 9         23 $self->{'variables'}->{$varName} = $val;
330            
331 9 50       34 VoiceXML::Client::Util::log_msg("SETTING $varName to '$val'") if ($VoiceXML::Client::Debug > 1);
332             }
333            
334 17 100       54 $self->{'variables'}->{$varName} = undef unless (exists $self->{'variables'}->{$varName});
335            
336            
337 17         71 return $self->{'variables'}->{$varName};
338             }
339              
340             sub clearGlobalVar {
341 4     4 0 6 my $self = shift;
342 4   50     12 my $varName = shift || return;
343            
344 4 50       14 if (exists $self->{'variables'}->{$varName})
345             {
346 4         15 $self->{'variables'}->{$varName} = undef;
347             }
348             }
349            
350             sub pushPositionStack {
351 1     1 0 3 my $self = shift;
352              
353 1         7 unshift @{$self->{'itempositionstack'}}, $self->{'currentitem'} ;
  1         5  
354            
355            
356             }
357              
358             sub latestPositionInStack {
359 1     1 0 2 my $self = shift;
360            
361            
362 1 50       1 if (scalar @{$self->{'itempositionstack'}})
  1         5  
363             {
364 1         4 return $self->{'itempositionstack'}->[0];
365             }
366            
367 0         0 return undef;
368            
369             }
370              
371             sub popPositionStack {
372 1     1 0 2 my $self = shift;
373            
374            
375 1 50       2 if (scalar @{$self->{'itempositionstack'}})
  1         4  
376             {
377 1         3 return shift @{$self->{'itempositionstack'}};
  1         2  
378             }
379              
380 0         0 return undef;
381             }
382              
383             sub execute {
384 3     3 0 18 my $self = shift;
385 3   50     13 my $handle = shift || return undef;
386 3   50     23 my $params = shift || {};
387 3   33     22 my $itemToExec = shift || $self->getNextItem();
388            
389 3 50       28 unless ($itemToExec)
390             {
391 0         0 warn "No form or other item to execute";
392 0         0 return undef;
393             }
394            
395 3         11 my $retVal = $VoiceXML::Client::Flow::Directive{'CONTINUE'};
396            
397 3   66     8 do {
      66        
398            
399 11         22 $self->{'nextform'} = undef; # make certain we start with a clean slate
400            
401 11         43 $retVal = $itemToExec->execute($handle, $params);
402            
403 11 100       50 $self->proceedToNextItem() if ($retVal != $VoiceXML::Client::Flow::Directive{'JUMP'});
404 11         27 $itemToExec = $self->getNextItem();
405            
406 11 100       77 if ($retVal == $VoiceXML::Client::Flow::Directive{'SUBRETURN'})
407             {
408 1         4 my $latestPosInStack = $self->latestPositionInStack();
409 1 50       4 if (defined $latestPosInStack)
410             {
411 1         3 $self->popPositionStack();
412 1         2 $self->{'currentitem'} = $latestPosInStack;
413 1         2 $itemToExec = $self->{'items'}->[$latestPosInStack];
414 1         6 $retVal = $VoiceXML::Client::Flow::Directive{'CONTINUE'};
415             }
416             }
417            
418            
419            
420             } while ($itemToExec &&
421             ($retVal == $VoiceXML::Client::Flow::Directive{'CONTINUE'}
422             ||
423             $retVal == $VoiceXML::Client::Flow::Directive{'JUMP'}));
424            
425            
426 3 50       12 if ($retVal == $VoiceXML::Client::Flow::Directive{'CONTINUE'})
427             {
428            
429            
430 0         0 warn "Made it through the entire VXML document but instructed to continue--aborting";
431 0         0 return $VoiceXML::Client::Flow::Directive{'ABORT'};
432             }
433              
434 3 50 33     183 return $retVal if ($retVal == $VoiceXML::Client::Flow::Directive{'ABORT'}
435             || $retVal == $VoiceXML::Client::Flow::Directive{'DONE'});
436            
437 0 0         if ($retVal == $VoiceXML::Client::Flow::Directive{'NEXTDOC'})
438             {
439             # need to jump somewhere...
440 0           my $nextDoc = $self->nextDocument();
441 0 0         warn "Told to go to next doc, but nextDocument not set" unless ($nextDoc);
442            
443 0 0         VoiceXML::Client::Util::log_msg("GOING TO $nextDoc") if ($VoiceXML::Client::Debug);
444            
445             }
446            
447 0           return $retVal;
448            
449             }
450            
451             sub nextDocument {
452 0     0 0   my $self = shift;
453 0           my $setTo = shift; # optional
454            
455 0 0         if (defined $setTo)
456             {
457 0           $self->{'nextdocument'} = $setTo;
458             }
459            
460 0           return $self->{'nextdocument'};
461             }
462            
463              
464             sub isaVXMLDocument {
465 0     0 0   my $self = shift;
466            
467 0           return 1;
468             }
469              
470             1;