/*******************************************************************************
* Copyright 2011 The Regents of the University of California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.ohmage.prompt.multichoicecustom;
import org.json.JSONArray;
import org.ohmage.AccountHelper;
import org.ohmage.OhmageMarkdown;
import org.ohmage.R;
import org.ohmage.UserPreferencesHelper;
import org.ohmage.Utilities.KVLTriplet;
import org.ohmage.activity.SurveyActivity;
import org.ohmage.prompt.AbstractPrompt;
import org.ohmage.prompt.CustomChoiceListView;
import android.content.Context;
import android.database.Cursor;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CheckedTextView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class MultiChoiceCustomPrompt extends AbstractPrompt {
private static final String TAG = "MultiChoiceCustomPrompt";
private List<KVLTriplet> mChoices;
private final List<KVLTriplet> mCustomChoices;
private ArrayList<Integer> mSelectedIndexes;
public MultiChoiceCustomPrompt() {
super();
mSelectedIndexes = new ArrayList<Integer>();
mCustomChoices = new ArrayList<KVLTriplet>();
mEnteredText = "";
mIsAddingNewItem = false;
}
public void setChoices(List<KVLTriplet> choices) {
if (choices != null) {
mChoices = choices;
} else {
mChoices = new ArrayList<KVLTriplet>();
}
}
public List<KVLTriplet> getChoices(){
return mChoices;
}
@Override
protected void clearTypeSpecificResponseData() {
if (mSelectedIndexes == null) {
mSelectedIndexes = new ArrayList<Integer>();
} else {
mSelectedIndexes.clear();
}
}
/**
* Always returns true as any selection of the items is considered valid.
*/
@Override
public boolean isPromptAnswered() {
return true;
}
@Override
protected Object getTypeSpecificResponseObject() {
JSONArray jsonArray = new JSONArray();
for (int index : mSelectedIndexes) {
if (index >= 0 && index < mChoices.size()) {
jsonArray.put(mChoices.get(index).label);
} else if (index < mChoices.size() + mCustomChoices.size()) {
jsonArray.put(mCustomChoices.get(index - mChoices.size()).label);
}
}
return jsonArray;
}
/**
* The text to be displayed to the user if the prompt is considered
* unanswered.
*/
@Override
public String getUnansweredPromptText() {
return("Please choose at least one of the items in the list.");
}
@Override
protected Object getTypeSpecificExtrasObject() {
return null;
}
private View mFooterView;
private ListView mListView;
private boolean mIsAddingNewItem;
private String mEnteredText;
private int mLastIndex;
private int mLastTop;
@Override
public View getView(final Context context) {
mCustomChoices.clear();
MultiChoiceCustomDbAdapter dbAdapter = new MultiChoiceCustomDbAdapter(context);
String surveyId = ((SurveyActivity)context).getSurveyId();
AccountHelper prefs = new AccountHelper(context);
String campaignUrn = ((SurveyActivity)context).getCampaignUrn();
String username = prefs.getUsername();
if (dbAdapter.open()) {
Cursor c = dbAdapter.getCustomChoices(username, campaignUrn, surveyId, MultiChoiceCustomPrompt.this.getId());
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
//c.getLong(c.getColumnIndex(MultiChoiceCustomDbAdapter.KEY_ID));
int key = c.getInt(c.getColumnIndex(MultiChoiceCustomDbAdapter.KEY_CHOICE_ID));
String label = c.getString(c.getColumnIndex(MultiChoiceCustomDbAdapter.KEY_CHOICE_VALUE));
mCustomChoices.add(new KVLTriplet(String.valueOf(key), null, label));
c.moveToNext();
}
c.close();
dbAdapter.close();
}
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// mListView = (ListView) inflater.inflate(R.layout.prompt_single_choice_custom, null);
mListView = new CustomChoiceListView(context);
mListView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
mListView.setTextFilterEnabled(false);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
mListView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mFooterView = inflater.inflate(R.layout.custom_choice_footer, null);
EditText mEditText = (EditText) mFooterView.findViewById(R.id.new_choice_edit);
ImageButton mButton = (ImageButton) mFooterView.findViewById(R.id.ok_button);
ImageButton mCancelButton = (ImageButton) mFooterView.findViewById(R.id.cancel_button);
showAddItemControls(context, mIsAddingNewItem);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mEnteredText = mEnteredText.trim();
if (!TextUtils.isEmpty(mEnteredText)) {
MultiChoiceCustomDbAdapter dbAdapter = new MultiChoiceCustomDbAdapter(context);
String surveyId = ((SurveyActivity)context).getSurveyId();
AccountHelper prefs = new AccountHelper(context);
String campaignUrn = ((SurveyActivity)context).getCampaignUrn();
String username = prefs.getUsername();
boolean duplicate = false;
int choiceId = 100;
ArrayList<String> keys = new ArrayList<String>();
for (KVLTriplet choice : mChoices) {
keys.add(choice.key.trim());
if(mEnteredText.toLowerCase().equals(choice.label.toLowerCase()))
duplicate = true;
}
for (KVLTriplet choice : mCustomChoices) {
keys.add(choice.key.trim());
if(mEnteredText.toLowerCase().equals(choice.label.toLowerCase()))
duplicate = true;
}
while ( keys.contains(String.valueOf(choiceId))) {
choiceId++;
}
if(duplicate) {
Toast.makeText(v.getContext(), v.getContext().getString(R.string.prompt_custom_choice_duplicate), Toast.LENGTH_SHORT).show();
} else if(!dbAdapter.open()) {
Toast.makeText(v.getContext(), v.getContext().getString(R.string.prompt_custom_choice_db_open_error), Toast.LENGTH_SHORT).show();
} else {
dbAdapter.addCustomChoice(choiceId, mEnteredText, username, campaignUrn, surveyId, MultiChoiceCustomPrompt.this.getId());
dbAdapter.close();
}
showAddItemControls(context, false);
mSelectedIndexes.add(Integer.valueOf(mListView.getCount() - 1));
((SurveyActivity)context).reloadCurrentPrompt();
} else {
Toast.makeText(context, "Please enter some text", Toast.LENGTH_SHORT).show();
}
}
});
mCancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// EditText edit = (EditText) mFooterView.findViewById(R.id.new_choice_edit);
showAddItemControls(context, false);
}
});
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
mEnteredText = s.toString();
// mListView.setSelectionFromTop(mLastIndex, mLastTop);
// EditText editText = (EditText) mFooterView.findViewById(R.id.new_choice_edit);
// editText.requestFocus();
}
});
mListView.addFooterView(mFooterView);
String [] from = new String [] {"value"};
int [] to = new int [] {android.R.id.text1};
List<HashMap<String, CharSequence>> data = new ArrayList<HashMap<String, CharSequence>>();
for (int i = 0; i < mChoices.size(); i++) {
HashMap<String, CharSequence> map = new HashMap<String, CharSequence>();
map.put("key", mChoices.get(i).key);
map.put("value", OhmageMarkdown.parse(mChoices.get(i).label));
data.add(map);
}
for (int i = 0; i < mCustomChoices.size(); i++) {
HashMap<String, CharSequence> map = new HashMap<String, CharSequence>();
map.put("key", mCustomChoices.get(i).key);
map.put("value", OhmageMarkdown.parse(mCustomChoices.get(i).label));
data.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(context, data, R.layout.multi_choice_list_item, from, to);
adapter.setViewBinder(new ViewBinder() {
@Override
public boolean setViewValue(View view, Object data, String textRepresentation) {
((CheckedTextView) view).setText((SpannableStringBuilder) data);
return true;
}
});
mListView.setAdapter(adapter);
if (mSelectedIndexes.size() > 0) {
for (int index : mSelectedIndexes) {
if (index >= 0 && index < mChoices.size() + mCustomChoices.size())
mListView.setItemChecked(index, true);
}
}
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == mListView.getCount() - 1) {
showAddItemControls(context, true);
mLastIndex = mListView.getLastVisiblePosition();
View v = mListView.getChildAt(mLastIndex);
mLastTop = (v == null) ? 0 : v.getTop();
mListView.setSelectionFromTop(mLastIndex, mLastTop);
} else {
//SparseBooleanArray checkItemPositions = ((ListView)parent).getCheckedItemPositions();
if (((ListView)parent).isItemChecked(position)) {
mSelectedIndexes.add(Integer.valueOf(position));
} else {
mSelectedIndexes.remove(Integer.valueOf(position));
}
}
}
});
mListView.setSelectionFromTop(mLastIndex, mLastTop);
return mListView;
}
private void showAddItemControls(Context context, boolean show) {
ImageView imageView = (ImageView) mFooterView.findViewById(R.id.image);
TextView textView = (TextView) mFooterView.findViewById(R.id.text);
EditText editText = (EditText) mFooterView.findViewById(R.id.new_choice_edit);
ImageButton mButton = (ImageButton) mFooterView.findViewById(R.id.ok_button);
ImageButton mCancelButton = (ImageButton) mFooterView.findViewById(R.id.cancel_button);
//editText.setText("");
InputMethodManager imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (show) {
editText.setText(mEnteredText);
mIsAddingNewItem = true;
imageView.setVisibility(View.GONE);
textView.setVisibility(View.GONE);
editText.setVisibility(View.VISIBLE);
mButton.setVisibility(View.VISIBLE);
mCancelButton.setVisibility(View.VISIBLE);
editText.requestFocus();
imm.showSoftInput(editText, 0);
} else {
mEnteredText = "";
mIsAddingNewItem = false;
imageView.setVisibility(View.VISIBLE);
textView.setVisibility(View.VISIBLE);
editText.setVisibility(View.GONE);
mButton.setVisibility(View.GONE);
mCancelButton.setVisibility(View.GONE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
}
@Override
public void setDefaultValue(String defaultValue) {
this.mDefaultValue = defaultValue;
try {
if(defaultValue != null) {
String[] values = defaultValue.split(",");
for(int i=0; i<values.length; i++)
mSelectedIndexes.add(Integer.valueOf(values[i]));
}
} catch(NumberFormatException e) {
// No number...
}
}
@Override
public void onHidden() {
mEnteredText = "";
mIsAddingNewItem = false;
}
public List<Integer> getSelectedIndexes() {
ArrayList<Integer> list = new ArrayList<Integer>();
for (int index : mSelectedIndexes) {
if (index >= 0 && index < mChoices.size()) {
list.add(index);
}
}
return list;
}
}