MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sequencecontainer.cpp
1 // © Copyright 2010 - 2012 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _inputsequencecontainer_cpp
41 #define _inputsequencecontainer_cpp
42 
43 #include "Input/sequencecontainer.h"
44 #include "timer.h"
45 #include "exception.h"
46 
47 #include <limits>
48 
49 namespace Mezzanine
50 {
51  namespace Input
52  {
54  MaxSequenceSize(0),
55  DeviceIndex(std::numeric_limits<UInt32>::max()),
56  SequencedInputs(MetaCode())
57  {
58  this->SequenceTimer = new StopWatchTimer();
59  this->SequenceTimer->SetInitialTimeInMilliseconds(300);
60  this->SequenceTimer->SetAutoReset(true);
61  this->SequenceTimer->Reset();
62  }
63 
65  MaxSequenceSize(0),
66  DeviceIndex(Device),
67  SequencedInputs(MetaCode())
68  {
69  this->SequenceTimer = new StopWatchTimer();
70  this->SequenceTimer->SetInitialTimeInMilliseconds(300);
71  this->SequenceTimer->SetAutoReset(true);
72  this->SequenceTimer->Reset();
73  }
74 
76  {
77  delete SequenceTimer;
78  this->SequencedInputs.clear();
79  }
80 
81  void SequenceContainer::VerifyInputSequence(const MetaCodeContainer& Codes) const
82  {
83  const Input::MetaCode NullCode;
84  if( Codes.size() < 3 )
85  {
86  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Attempting to add a Sequenced Input that is less then 3 MetaCodes long(including the Null MetaCode). "
87  "A sequence with only one(or less) actual MetaCode isn't a sequence.");
88  }
89  if( NullCode != Codes.back() )
90  { MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Attempting to add a Sequenced Input that is not terminated with a null MetaCode."); }
91  }
92 
94  {
95  if( std::numeric_limits<Int32>::max() == ID )
96  { MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Attempting to use max value of Int32 as an ID for an input sequence. This value is reserved for error conditions."); }
97  }
98 
99  MetaCode SequenceContainer::ProcessSequence(MetaCodeIterator First, MetaCodeIterator OneAfterLast)
100  {
101  // Set up our data
102  MetaCode Ret;
103  MetaCodeContainer Key(this->CurrSequenceCache.begin(),this->CurrSequenceCache.end());
104  Key.push_back(this->SequencedInputs.endSymbol());
105  // Do the actual search
106  SequencedInputIterator SeqIt = this->SequencedInputs.find(Key);
107  // Return a "Null" metacode if nothing was found
108  if( SeqIt == this->SequencedInputs.end() ) return Ret;
109  else
110  {
111  Ret.SetCode(Input::COMPOUNDINPUT_CUSTOMSEQUENCE);
112  Ret.SetMetaValue( *(*SeqIt).second );
113  Ret.SetDeviceIndex(this->DeviceIndex);
114  return Ret;
115  }
116  }
117 
118  ///////////////////////////////////////////////////////////////////////////////
119  // Sequenced Input Management
120 
121  void SequenceContainer::AddInputSequence(const MetaCodeContainer& Codes, const Int32& SequenceID)
122  {
123  this->VerifyInputSequence(Codes);
124  this->VerifyInputID(SequenceID);
125  this->SequencedInputs.insert(Codes,SequenceID);
126  if( this->MaxSequenceSize < Codes.size() - 1 )
127  this->MaxSequenceSize = Codes.size() - 1;
128  }
129 
130  bool SequenceContainer::InputSequenceExists(const MetaCodeContainer& Codes)
131  {
132  this->VerifyInputSequence(Codes);
133  return this->SequencedInputs.hasKey(Codes);
134  }
135 
136  Int32 SequenceContainer::GetIDofInputSequence(const MetaCodeContainer& Codes)
137  {
138  this->VerifyInputSequence(Codes);
139  SequencedInputIterator SqIt = this->SequencedInputs.find(Codes);
140  if( SqIt != this->SequencedInputs.end() ) return *(SqIt->second);
141  else return std::numeric_limits<Int32>::max();
142 
143  /*UInt32* Ret = SequencedInputs.get(Codes);
144  if(Ret) return *Ret;
145  else return ULONG_MAX;//*/
146  }
147 
148  void SequenceContainer::RemoveInputSequence(const MetaCodeContainer& Codes)
149  {
150  this->VerifyInputSequence(Codes);
151  this->SequencedInputs.erase(Codes);
152  }
153 
155  {
156  this->SequencedInputs.clear();
157  }
158 
159  ///////////////////////////////////////////////////////////////////////////////
160  // Utility
161 
163  {
164  return static_cast<UInt32>(this->SequencedInputs.size());
165  }
166 
167  void SequenceContainer::Update(const MetaCodeContainer& NormalCodes, MetaCodeContainer& SequenceCodes)
168  {
169  // Set up our compare data
170  const MetaCode NullMetaCode;
171  // Escape early if we have nothing to do
172  if(this->SequencedInputs.empty())
173  return;
174 
175  // Check our timer and clear our cache if it's been long enough since the last input
176  if( this->SequenceTimer->IsStopped() ) this->CurrSequenceCache.clear();
177  else this->SequenceTimer->Reset();
178 
179  // Perform our per-code processing
180  for( ConstMetaCodeIterator MCIt = NormalCodes.begin() ; MCIt != NormalCodes.end() ; ++MCIt )
181  {
182  if( this->CurrSequenceCache.empty() )
183  {
184  MetaCodeContainer TestVec;
185  TestVec.push_back( (*MCIt) );
186  TestVec.push_back(NullMetaCode);
187  SequencedInputIterator SeqIt = this->SequencedInputs.startsWith(TestVec);
188  if( SeqIt != this->SequencedInputs.end() )
189  {
190  this->CurrSequenceCache.push_back( (*MCIt) );
191  this->SequenceTimer->Start();
192  }
193  }else{
194  this->CurrSequenceCache.push_back( (*MCIt) );
195  if( this->MaxSequenceSize == this->CurrSequenceCache.size() )
196  {
197  // Commented out the line below since we shouldn't ever encounter a case where the size is more then 1 greater, since we process one MetaCode at a time
198  //MetaCodeContainer SwapVec(CurrSequenceCache.begin() + ( CurrSequenceCache.size() - MaxSequenceSize ),CurrSequenceCache.end());
199  this->CurrSequenceCache.erase(this->CurrSequenceCache.begin());
200  }
201  else if( this->MaxSequenceSize < this->CurrSequenceCache.size() )
202  {
203  MEZZ_EXCEPTION(Exception::INVALID_STATE_EXCEPTION,"Somehow managed to have the sequence cache in this SequenceContainer jump to more than 1 greater than the longest stored sequence. "
204  "Don't know how that happened, but if you see this error then the class needs a patch.");
205  }
206  // Compare current cache to existing stored sequences
207  MetaCode New = this->ProcessSequence(this->CurrSequenceCache.begin(),this->CurrSequenceCache.end());
208  if( NullMetaCode != New )
209  SequenceCodes.push_back(New);
210  }
211  }
212  }
213  }//Input
214 }//Mezzanine
215 
216 #endif