1 /*
2  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
3  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
4  * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program 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 this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 
21 package org.hedgewars.hedgeroid;
22 
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.NoSuchElementException;
30 
31 import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
32 import org.hedgewars.hedgeroid.Datastructures.Hog;
33 import org.hedgewars.hedgeroid.Datastructures.Team;
34 import org.hedgewars.hedgeroid.util.FileUtils;
35 
36 import android.app.Activity;
37 import android.graphics.Bitmap;
38 import android.graphics.drawable.Drawable;
39 import android.media.MediaPlayer;
40 import android.os.Bundle;
41 import android.util.Log;
42 import android.view.View;
43 import android.view.View.OnClickListener;
44 import android.widget.AdapterView;
45 import android.widget.AdapterView.OnItemSelectedListener;
46 import android.widget.ArrayAdapter;
47 import android.widget.EditText;
48 import android.widget.ImageButton;
49 import android.widget.ImageView;
50 import android.widget.LinearLayout;
51 import android.widget.RelativeLayout;
52 import android.widget.ScrollView;
53 import android.widget.SimpleAdapter;
54 import android.widget.Spinner;
55 import android.widget.SpinnerAdapter;
56 import android.widget.TextView;
57 import android.widget.Toast;
58 
59 /**
60  * Edit or create a team. If a team should be edited, it is supplied in the extras
61  * as parameter oldTeamName.
62  */
63 public class TeamCreatorActivity extends Activity implements Runnable {
64     public static final String PARAMETER_EXISTING_TEAMNAME = "existingTeamName";
65     private static final String TAG = TeamCreatorActivity.class.getSimpleName();
66 
67     private TextView name;
68     private Spinner difficulty, grave, flag, voice, fort;
69     private ImageView imgFort;
70     private ArrayList<ImageButton> hogDice = new ArrayList<ImageButton>();
71     private ArrayList<Spinner> hogHat = new ArrayList<Spinner>();
72     private ArrayList<EditText> hogName = new ArrayList<EditText>();
73     private ImageButton voiceButton;
74     private ScrollView scroller;
75     private MediaPlayer mp = null;
76     private boolean initComplete = false;
77 
78     private String existingTeamName = null;
79 
80     private final List<Map<String, ?>> flagsData = new ArrayList<Map<String, ?>>();
81     private final List<Map<String, ?>> typesData = new ArrayList<Map<String, ?>>();
82     private final List<Map<String, ?>> gravesData = new ArrayList<Map<String, ?>>();
83     private final List<Map<String, ?>> hatsData = new ArrayList<Map<String, ?>>();
84     private final List<String> voicesData = new ArrayList<String>();
85     private final List<String> fortsData = new ArrayList<String>();
86 
onCreate(Bundle savedInstanceState)87     public void onCreate(Bundle savedInstanceState) {
88         super.onCreate(savedInstanceState);
89         initComplete = false;
90 
91         // Restore state and read parameters
92         if(savedInstanceState != null) {
93             existingTeamName = savedInstanceState.getString(PARAMETER_EXISTING_TEAMNAME);
94         } else {
95             existingTeamName = getIntent().getStringExtra(PARAMETER_EXISTING_TEAMNAME);
96         }
97 
98         // Set up view
99         setContentView(R.layout.team_creation);
100 
101         name = (TextView) findViewById(R.id.txtName);
102         difficulty = (Spinner) findViewById(R.id.spinType);
103         grave = (Spinner) findViewById(R.id.spinGrave);
104         flag = (Spinner) findViewById(R.id.spinFlag);
105         voice = (Spinner) findViewById(R.id.spinVoice);
106         fort = (Spinner) findViewById(R.id.spinFort);
107 
108         imgFort = (ImageView) findViewById(R.id.imgFort);
109 
110         voiceButton = (ImageButton) findViewById(R.id.btnPlay);
111 
112         scroller = (ScrollView) findViewById(R.id.scroller);
113 
114         // Wire view elements
115         LinearLayout ll = (LinearLayout) findViewById(R.id.HogsContainer);
116         for (int i = 0; i < ll.getChildCount(); i++) {
117             RelativeLayout team_creation_entry = (RelativeLayout) ll.getChildAt(i);
118 
119             hogHat.add((Spinner) team_creation_entry
120                     .findViewById(R.id.spinTeam1));
121             hogDice.add((ImageButton) team_creation_entry
122                     .findViewById(R.id.btnTeam1));
123             hogName.add((EditText) team_creation_entry
124                     .findViewById(R.id.txtTeam1));
125         }
126 
127         grave.setAdapter(createMapSpinnerAdapter(gravesData));
128         flag.setAdapter(createMapSpinnerAdapter(flagsData));
129         difficulty.setAdapter(createMapSpinnerAdapter(typesData));
130         SpinnerAdapter hatAdapter = createMapSpinnerAdapter(hatsData);
131         for (Spinner spin : hogHat) {
132             spin.setAdapter(hatAdapter);
133         }
134 
135 
136         voice.setAdapter(createListSpinnerAdapter(voicesData));
137         voiceButton.setOnClickListener(voiceClicker);
138 
139         fort.setAdapter(createListSpinnerAdapter(fortsData));
140         fort.setOnItemSelectedListener(fortSelector);
141 
142         new Thread(this).start();
143     }
144 
createMapSpinnerAdapter(List<? extends Map<String, ?>> data)145     private SpinnerAdapter createMapSpinnerAdapter(List<? extends Map<String, ?>> data) {
146         SimpleAdapter sa = new SimpleAdapter(this, data,
147                 R.layout.spinner_textimg_entry, new String[] { "txt", "img" },
148                 new int[] { R.id.spinner_txt, R.id.spinner_img });
149         sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry);
150         sa.setViewBinder(viewBinder);
151         return sa;
152     }
153 
createListSpinnerAdapter(List<String> data)154     private SpinnerAdapter createListSpinnerAdapter(List<String> data) {
155         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, data);
156         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
157         return adapter;
158     }
159 
run()160     public void run(){
161         try {
162             final List<Map<String, ?>> gravesDataNew = FrontendDataUtils.getGraves(this);
163             runOnUiThread(new Runnable(){
164                 public void run() {
165                     gravesData.addAll(gravesDataNew);
166                     ((SimpleAdapter)grave.getAdapter()).notifyDataSetChanged();
167                 }
168             });
169 
170             final List<Map<String, ?>> flagsDataNew = FrontendDataUtils.getFlags(this);
171             runOnUiThread(new Runnable(){
172                 public void run() {
173                     flagsData.addAll(flagsDataNew);
174                     ((SimpleAdapter)flag.getAdapter()).notifyDataSetChanged();
175                 }
176             });
177 
178             final List<Map<String, ?>> typesDataNew = FrontendDataUtils.getTypes(this);
179             runOnUiThread(new Runnable(){
180                 public void run() {
181                     typesData.addAll(typesDataNew);
182                     ((SimpleAdapter)difficulty.getAdapter()).notifyDataSetChanged();
183                 }
184             });
185 
186             final List<Map<String, ?>> hatsDataNew = FrontendDataUtils.getHats(this);
187             runOnUiThread(new Runnable(){
188                 public void run() {
189                     hatsData.addAll(hatsDataNew);
190                     ((SimpleAdapter)hogHat.get(0).getAdapter()).notifyDataSetChanged();
191                 }
192             });
193 
194             final List<String> voicesDataNew = FrontendDataUtils.getVoices(this);
195             runOnUiThread(new Runnable(){
196                 public void run() {
197                     voicesData.addAll(voicesDataNew);
198                     ((ArrayAdapter<?>)voice.getAdapter()).notifyDataSetChanged();
199                 }
200             });
201 
202             final List<String> fortsDataNew = FrontendDataUtils.getForts(this);
203             runOnUiThread(new Runnable(){
204                 public void run() {
205                     fortsData.addAll(fortsDataNew);
206                     ((ArrayAdapter<?>)fort.getAdapter()).notifyDataSetChanged();
207                 }
208             });
209 
210             if(existingTeamName!=null) {
211                 final Team loadedTeam = Team.load(Team.getTeamfileByName(getApplicationContext(), existingTeamName));
212                 if(loadedTeam==null) {
213                     existingTeamName = null;
214                 } else {
215                     runOnUiThread(new Runnable(){
216                         public void run() {
217                             setTeamValues(loadedTeam);
218                         }
219                     });
220                 }
221             }
222             runOnUiThread(new Runnable(){
223                 public void run() {
224                     initComplete = true;
225                 }
226             });
227         } catch(FileNotFoundException e) {
228             this.runOnUiThread(new Runnable(){
229                 public void run() {
230                     Toast.makeText(getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
231                     finish();
232                 }
233             });
234         }
235     }
236 
onDestroy()237     public void onDestroy() {
238         super.onDestroy();
239         if (mp != null) {
240             mp.release();
241             mp = null;
242         }
243     }
244 
245     @Override
onSaveInstanceState(Bundle outState)246     protected void onSaveInstanceState(Bundle outState) {
247         super.onSaveInstanceState(outState);
248         outState.putString(PARAMETER_EXISTING_TEAMNAME, existingTeamName);
249     }
250 
onBackPressed()251     public void onBackPressed() {
252         if(initComplete) {
253             saveTeam();
254         }
255         setResult(RESULT_OK);
256         super.onBackPressed();
257     }
258 
saveTeam()259     private void saveTeam() {
260         String teamName = name.getText().toString();
261         String teamFlag = (String)((Map<String, Object>) flag.getSelectedItem()).get("txt");
262         String teamFort = fort.getSelectedItem().toString();
263         String teamGrave = (String)((Map<String, Object>) grave.getSelectedItem()).get("txt");
264         String teamVoice = voice.getSelectedItem().toString();
265         int levelInt = (Integer)((Map<String, Object>) difficulty.getSelectedItem()).get("level");
266 
267         List<Hog> hogs = new ArrayList<Hog>();
268         for (int i = 0; i < hogName.size(); i++) {
269             String name = hogName.get(i).getText().toString();
270             String hat = ((Map<String, Object>) hogHat.get(i).getSelectedItem()).get("txt").toString();
271             hogs.add(new Hog(name, hat, levelInt));
272         }
273 
274         Team team = new Team(teamName, teamGrave, teamFlag, teamVoice, teamFort, hogs);
275         File teamsDir = new File(getFilesDir(), Team.DIRECTORY_TEAMS);
276         if (!teamsDir.exists()) teamsDir.mkdir();
277 
278         File newFile = Team.getTeamfileByName(this, teamName);
279         File oldFile = null;
280         if(existingTeamName != null) {
281             oldFile = Team.getTeamfileByName(this, existingTeamName);
282         }
283         try {
284             team.save(newFile);
285             // If the team was renamed, delete the old file.
286             if(oldFile != null && oldFile.isFile() && !oldFile.equals(newFile)) {
287                 oldFile.delete();
288             }
289             existingTeamName = teamName;
290         } catch(IOException e) {
291             Toast.makeText(getApplicationContext(), R.string.error_save_failed, Toast.LENGTH_SHORT).show();
292         }
293     };
294 
295     private OnItemSelectedListener fortSelector = new OnItemSelectedListener() {
296         public void onItemSelected(AdapterView<?> arg0, View arg1,
297                 int position, long arg3) {
298             String fortName = (String) arg0.getAdapter().getItem(position);
299             try {
300                 File fortImage = FileUtils.getDataPathFile(TeamCreatorActivity.this, "Forts", fortName, "L.png");
301                 Drawable fortIconDrawable = Drawable.createFromPath(fortImage.getAbsolutePath());
302                 imgFort.setImageDrawable(fortIconDrawable);
303             } catch(IOException e) {
304                 Log.e(TAG, "Unable to show fort image", e);
305             }
306             scroller.fullScroll(ScrollView.FOCUS_DOWN);// Scroll the scrollview
307             // to the bottom, work
308             // around for scrollview
309             // invalidation (scrolls
310             // back to top)
311         }
312 
313         public void onNothingSelected(AdapterView<?> arg0) {
314         }
315 
316     };
317 
318     private OnClickListener voiceClicker = new OnClickListener() {
319         public void onClick(View v) {
320             try {
321                 File dir = FileUtils.getDataPathFile(TeamCreatorActivity.this, "Sounds", "voices", (String)voice.getSelectedItem());
322                 String file = "";
323                 File[] dirs = dir.listFiles();
324                 File f = dirs[(int) Math.round(Math.random() * dirs.length)];
325                 if (f.getName().endsWith(".ogg"))
326                     file = f.getAbsolutePath();
327 
328                 if (mp == null)
329                     mp = new MediaPlayer();
330                 else
331                     mp.reset();
332                 mp.setDataSource(file);
333                 mp.prepare();
334                 mp.start();
335             } catch (IllegalArgumentException e) {
336                 Log.e(TAG, "Unable to play voice sample", e);
337             } catch (IllegalStateException e) {
338                 Log.e(TAG, "Unable to play voice sample", e);
339             } catch (IOException e) {
340                 Log.e(TAG, "Unable to play voice sample", e);
341             }
342         }
343     };
344 
345     @SuppressWarnings("unchecked")
setTeamValues(Team t)346     private void setTeamValues(Team t){
347         if (t == null) {
348             return;
349         }
350 
351         try {
352             name.setText(t.name);
353             voice.setSelection(findPosition((ArrayAdapter<String>) voice.getAdapter(), t.voice));
354             fort.setSelection(findPosition((ArrayAdapter<String>) fort.getAdapter(), t.fort));
355             difficulty.setSelection(findPosition(typesData, "level", Integer.valueOf(t.hogs.get(0).level)));
356             grave.setSelection(findPosition(gravesData, "txt", t.grave));
357             flag.setSelection(findPosition(flagsData, "txt", t.flag));
358 
359             for (int i = 0; i < Team.HEDGEHOGS_PER_TEAM; i++) {
360                 hogHat.get(i).setSelection(findPosition(hatsData, "txt", t.hogs.get(i).hat));
361                 hogName.get(i).setText(t.hogs.get(i).name);
362             }
363         } catch(NoSuchElementException e) {
364             Toast.makeText(getApplicationContext(), R.string.error_team_attribute_not_found, Toast.LENGTH_LONG).show();
365             finish();
366         }
367     }
368 
findPosition(ArrayAdapter<String> adapter, String value)369     int findPosition(ArrayAdapter<String> adapter, String value) throws NoSuchElementException {
370         int position = adapter.getPosition(value);
371         if(position<0) {
372             throw new NoSuchElementException();
373         }
374         return position;
375     }
376 
findPosition(List<? extends Map<String, ?>> data, String key, Object value)377     int findPosition(List<? extends Map<String, ?>> data, String key, Object value) throws NoSuchElementException {
378         int position = 0;
379         for (Map<String, ?> map : data) {
380             if (map.get(key).equals(value)) {
381                 return position;
382             }
383             position++;
384         }
385         throw new NoSuchElementException();
386     }
387 
388     private SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() {
389 
390         public boolean setViewValue(View view, Object data,
391                 String textRepresentation) {
392             if (view instanceof ImageView && data instanceof Bitmap) {
393                 ImageView v = (ImageView) view;
394                 v.setImageBitmap((Bitmap) data);
395                 return true;
396             } else {
397                 return false;
398             }
399         }
400     };
401 }
402