Project

General

Profile

Download (13 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / network / RubikScores.java @ 8ab435b9

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.network;
21

    
22
import java.util.UUID;
23

    
24
import android.content.Context;
25
import android.content.SharedPreferences;
26
import android.telephony.TelephonyManager;
27

    
28
import com.google.firebase.crashlytics.FirebaseCrashlytics;
29

    
30
import static org.distorted.objectlib.main.ObjectType.NUM_OBJECTS;
31
import static org.distorted.screens.RubikScreenPlay.MAX_LEVEL;
32

    
33
import org.distorted.objectlib.main.ObjectType;
34

    
35
import org.distorted.main.BuildConfig;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38
// hold my own scores, and some other statistics.
39

    
40
public class RubikScores
41
  {
42
  public static final long NO_RECORD = Long.MAX_VALUE;
43
  private static RubikScores mThis;
44

    
45
  private final long[][] mRecords;
46
  private final int [][] mSubmitted;
47

    
48
  private String mName, mCountry;
49
  private boolean mNameIsVerified;
50
  private int mNumRuns;
51
  private int mNumPlays;
52
  private int mNumWins;
53
  private int mDeviceID;
54

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56

    
57
  private RubikScores()
58
    {
59
    mRecords   = new long[NUM_OBJECTS][MAX_LEVEL];
60
    mSubmitted = new int [NUM_OBJECTS][MAX_LEVEL];
61

    
62
    for(int object=0; object<NUM_OBJECTS; object++)
63
      for(int level=0; level<MAX_LEVEL; level++)
64
        {
65
        mRecords[object][level]   = NO_RECORD;
66
        mSubmitted[object][level] = 0;
67
        }
68

    
69
    mName = "";
70
    mCountry = "un";
71

    
72
    mNameIsVerified = false;
73

    
74
    mNumPlays= -1;
75
    mNumRuns = -1;
76
    mDeviceID= -1;
77
    mNumWins =  0;
78
    }
79

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81

    
82
  private int privateGetDeviceID()
83
    {
84
    int id;
85

    
86
    try
87
      {
88
      String s = UUID.randomUUID().toString();
89
      id = s.hashCode();
90
      }
91
    catch(Exception ex)
92
      {
93
      id = 0;
94
      android.util.Log.e("scores", "Exception in getDeviceID()");
95
      }
96

    
97
    return id<0 ? -id : id;
98
    }
99

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

    
102
  synchronized void successfulSubmit()
103
    {
104
    mNameIsVerified = true;
105

    
106
    for(int object=0; object<NUM_OBJECTS; object++)
107
      for(int level=0; level<MAX_LEVEL; level++)
108
        {
109
        mSubmitted[object][level]=1;
110
        }
111
    }
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114

    
115
  int getDeviceID()
116
    {
117
    return mDeviceID;
118
    }
119

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

    
122
  synchronized boolean thereAreUnsubmittedRecords()
123
    {
124
    for(int object=0; object<NUM_OBJECTS; object++)
125
      for(int level=0; level<MAX_LEVEL; level++)
126
        {
127
        if( mSubmitted[object][level]==0 && mRecords[object][level]<NO_RECORD ) return true;
128
        }
129

    
130
    return false;
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  synchronized String getRecordList(String strObj, String strLvl, String strTim)
136
    {
137
    StringBuilder builderObj = new StringBuilder();
138
    StringBuilder builderLvl = new StringBuilder();
139
    StringBuilder builderTim = new StringBuilder();
140
    boolean first = true;
141

    
142
    for(int object=0; object<NUM_OBJECTS; object++)
143
      {
144
      String name = ObjectType.getObject(object).name();
145

    
146
      for(int level=0; level<MAX_LEVEL; level++)
147
        {
148
        if( mSubmitted[object][level]==0 && mRecords[object][level]<NO_RECORD )
149
          {
150
          if( !first )
151
            {
152
            builderObj.append(',');
153
            builderLvl.append(',');
154
            builderTim.append(',');
155
            }
156
          first=false;
157

    
158
          builderObj.append(name);
159
          builderLvl.append(level);
160
          builderTim.append(mRecords[object][level]);
161
          }
162
        }
163
      }
164

    
165
    return strObj+builderObj.toString()+strLvl+builderLvl.toString()+strTim+builderTim.toString();
166
    }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169
// Public API
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

    
172
  public synchronized long getRecord(int obj, int level)
173
    {
174
    return (obj>=0 && obj<NUM_OBJECTS && level>=0 && level<MAX_LEVEL) ? mRecords[obj][level] : -1;
175
    }
176

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178

    
179
  public boolean isVerified()
180
    {
181
    return mNameIsVerified;
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  public int getNumPlays()
187
    {
188
    return mNumPlays;
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  public int getNumRuns()
194
    {
195
    return mNumRuns;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  public String getName()
201
    {
202
    return mName;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
  public String getCountry()
208
    {
209
    return mCountry;
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  public void incrementNumPlays()
215
    {
216
    mNumPlays++;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  public void incrementNumRuns()
222
    {
223
    mNumRuns++;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  public int incrementNumWins()
229
    {
230
    mNumWins++;
231
    return mNumWins;
232
    }
233

    
234
///////////////////////////////////////////////////////////////////////////////////////////////////
235

    
236
  public void setName(String newName)
237
    {
238
    mName = newName;
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  public synchronized boolean isSolved(int obj, int level)
244
    {
245
    return obj>=0 && obj<NUM_OBJECTS && level>=0 && level<MAX_LEVEL && mRecords[obj][level]<NO_RECORD;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  public void setCountry(Context context)
251
    {
252
    TelephonyManager tM =((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
253

    
254
    if( tM!=null )
255
      {
256
      mCountry = tM.getSimCountryIso();
257

    
258
      if( mCountry==null || mCountry.length()<=1 )
259
        {
260
        mCountry = tM.getNetworkCountryIso();
261
        }
262
      }
263

    
264
    // Special case: Dominicana. Its ISO-3166-alpha-2 country code is 'do' which we can't have here
265
    // because we later on map this to a resource name (the flag) and 'do' is a reserved Java keyword
266
    // and can't be a resource name.
267

    
268
    if( mCountry.equals("do") ) mCountry = "dm";
269
    }
270

    
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272

    
273
  public void setCountry(String country)
274
    {
275
    mCountry = country;
276

    
277
    if( mCountry.equals("do") ) mCountry = "dm";  // see above
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  public static RubikScores getInstance()
283
    {
284
    if( mThis==null ) mThis = new RubikScores();
285
    return mThis;
286
    }
287

    
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289

    
290
  public synchronized void savePreferences(SharedPreferences.Editor editor)
291
    {
292
    StringBuilder builder = new StringBuilder();
293
    String name;
294

    
295
    for(int level=0; level<MAX_LEVEL; level++)
296
      {
297
      builder.setLength(0);
298

    
299
      for(int object=0; object<NUM_OBJECTS; object++)
300
        {
301
        name = ObjectType.getObject(object).name();
302
        builder.append(name);
303
        builder.append("=");
304
        builder.append(mRecords[object][level]);
305
        builder.append(",");
306
        builder.append(mSubmitted[object][level]);
307
        builder.append(" ");
308
        }
309

    
310
      editor.putString("scores_record"+level, builder.toString());
311
      }
312

    
313
    editor.putString("scores_name"  , mName  );
314
    editor.putBoolean("scores_isVerified", mNameIsVerified);
315
    editor.putInt("scores_numPlays", mNumPlays);
316
    editor.putInt("scores_numRuns" , mNumRuns );
317
    editor.putInt("scores_deviceid", mDeviceID);
318
    editor.putInt("scores_review"  , mNumWins );
319
    }
320

    
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322

    
323
  public synchronized void restorePreferences(SharedPreferences preferences)
324
    {
325
    String recordStr, subStr, nameStr, timeStr, submStr, errorStr="";
326
    int start, end, equals, comma, object, subm;
327
    long time;
328
    boolean thereWasError = false;
329

    
330
    for(int level=0; level<MAX_LEVEL; level++)
331
      {
332
      start = end = 0;
333
      recordStr = preferences.getString("scores_record"+level, "");
334

    
335
      while( end!=-1 )
336
        {
337
        end = recordStr.indexOf(" ", start);
338

    
339
        if( end==-1 ) subStr = recordStr.substring(start);
340
        else          subStr = recordStr.substring(start,end);
341

    
342
        start = end+1;
343

    
344
        equals = subStr.indexOf("=");
345
        comma  = subStr.indexOf(",");
346

    
347
        if( equals>=0 && comma>=0 )
348
          {
349
          nameStr = subStr.substring(0,equals);
350
          timeStr = subStr.substring(equals+1,comma);
351
          submStr = subStr.substring(comma+1);
352

    
353
          object = ObjectType.getOrdinal(nameStr);
354

    
355
          if( object>=0 && object< NUM_OBJECTS )
356
            {
357
            time = Long.parseLong(timeStr);
358
            subm = Integer.parseInt(submStr);
359

    
360
            if( subm>=0 && subm<=1 )
361
              {
362
              mRecords  [object][level] = time;
363
              mSubmitted[object][level] = subm;
364
              }
365
            else
366
              {
367
              errorStr += ("error1: subm="+subm+" obj: "+nameStr+"\n");
368
              thereWasError= true;
369
              }
370
            }
371
          else
372
            {
373
            errorStr += ("error2: object="+object+" obj: "+nameStr+"\n");
374
            thereWasError = true;
375
            }
376
          }
377
        }
378
      }
379

    
380
    mName           = preferences.getString("scores_name"  , "" );
381
    mNameIsVerified = preferences.getBoolean("scores_isVerified", false);
382
    mNumPlays       = preferences.getInt("scores_numPlays", 0);
383
    mNumRuns        = preferences.getInt("scores_numRuns" , 0);
384
    mDeviceID       = preferences.getInt("scores_deviceid",-1);
385
    mNumWins        = preferences.getInt("scores_review"  , 0);
386

    
387
    if( mDeviceID==-1 ) mDeviceID = privateGetDeviceID();
388

    
389
    if( thereWasError ) recordDBError(errorStr);
390
    }
391

    
392
///////////////////////////////////////////////////////////////////////////////////////////////////
393

    
394
  public void recordDBError(String message)
395
    {
396
    if( BuildConfig.DEBUG )
397
      {
398
      android.util.Log.e("scores", message);
399
      }
400
    else
401
      {
402
      Exception ex = new Exception(message);
403
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
404
      crashlytics.setCustomKey("scores" , message);
405
      crashlytics.recordException(ex);
406
      }
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  public synchronized boolean setRecord(int object, int level, long timeTaken)
412
    {
413
    if( object>=0 && object<NUM_OBJECTS && level>=1 && level<=MAX_LEVEL && mRecords[object][level-1]>timeTaken )
414
      {
415
      mRecords  [object][level-1] = timeTaken;
416
      mSubmitted[object][level-1] = 0;
417
      return true;
418
      }
419

    
420
    return false;
421
    }
422
  }
(2-2/2)