package org.openhab.habclient.rule;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.Toast;
import org.openhab.domain.IOpenHABWidgetProvider;
import org.openhab.domain.IUnitEntityDataTypeProvider;
import org.openhab.domain.model.OpenHABWidget;
import org.openhab.domain.rule.IRuleOperationBuildListener;
import org.openhab.domain.rule.IRuleOperatorProvider;
import org.openhab.domain.rule.UnitEntityDataType;
import org.openhab.habclient.HABApplication;
import org.openhab.habclient.dagger.DaggerRuleOperationComponent;
import org.openhab.habdroid.R;
import org.openhab.domain.rule.EntityDataTypeSource;
import org.openhab.domain.rule.IEntityDataType;
import org.openhab.domain.rule.RuleOperation;
import org.openhab.domain.rule.operators.RuleOperator;
import org.openhab.domain.rule.RuleOperatorType;
import org.openhab.domain.rule.RuleTreeItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.inject.Inject;
public class RuleOperationFragment extends Fragment implements IRuleOperationBuildListener {
private final String TAG = "RuleOperationFragment";
private ExpandableMultiLevelGroupAdapter mTreeListAdapter;
private ExpandableListView mTreeView;
private SparseArray<RuleTreeItem> mTreeData;
private RuleTreeItem mSelectedTreeItem;
private RuleOperation mOperationUnderConstruction;
private EditText mRuleNameView;
@Inject IOpenHABWidgetProvider mWidgetProvider;
@Inject IRuleOperatorProvider mRuleOperationProvider;
@Inject IUnitEntityDataTypeProvider mUnitEntityDataTypeProvider;
@Inject IAdapterProvider mAdapterProvider;
public static RuleOperationFragment newInstance() {
return new RuleOperationFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerRuleOperationComponent.builder()
.appComponent(((HABApplication)getActivity().getApplication()).appComponent())
.build()
.inject(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(HABApplication.getLogTag(), "RuleOperationFragment.onCreateView()");
View view = inflater.inflate(R.layout.fragment_rule_operation, container, false);
mRuleNameView = (EditText) view.findViewById(R.id.rule_name_textview);
mTreeView = (ExpandableListView) view.findViewById(R.id.rule_if_tree);
mTreeData = new SparseArray<RuleTreeItem>();
mTreeListAdapter = new ExpandableMultiLevelGroupAdapter(getActivity(), mTreeData);
mTreeView.setAdapter(mTreeListAdapter);
updateRuleTree(((RuleEditActivity) getActivity()).getRule().getRuleOperation());
((RuleEditActivity)getActivity()).setRuleOperationBuildListener(this);
mTreeView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
// Toast.makeText(getApplicationContext(),
// "Group Clicked " + listDataHeader.get(groupPosition),
// Toast.LENGTH_SHORT).show();
Toast.makeText(getActivity(), "OnGroupClickListener", Toast.LENGTH_SHORT).show();
return false;
}
});
mTreeView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
// Toast.makeText(
// getApplicationContext(),
// mTreeData.get(Integer.valueOf(groupPosition)).mName
// + " : "
// + mTreeData.get(Integer.valueOf(groupPosition)).mChildren.get(Integer.valueOf(childPosition)).mName, Toast.LENGTH_SHORT
// )
// .show();
mSelectedTreeItem = mTreeData.get(Integer.valueOf(groupPosition)).mChildren.get(Integer.valueOf(childPosition));
openOperationBuilderDialog(-1, mSelectedTreeItem);
return false;
}
});
mTreeView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
});
// Listview Group expanded listener
mTreeView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
mSelectedTreeItem = mTreeData.get(Integer.valueOf(groupPosition));
Toast.makeText(getActivity(),
mTreeData.get(Integer.valueOf(groupPosition)).getItemId() + " OnGroupExpandListener",
Toast.LENGTH_SHORT).show();
}
});
// Listview Group collasped listener
mTreeView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(getActivity(),
mTreeData.get(Integer.valueOf(groupPosition)).getItemId() + " OnGroupCollapseListener",
Toast.LENGTH_SHORT).show();
}
});
mTreeView.setOnLongClickListener(new ExpandableListView.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Toast.makeText(getActivity(), "ExpandableListView.OnLongClick", Toast.LENGTH_SHORT).show();
openOperationBuilderDialog(-1, mSelectedTreeItem);
return false;
}
});
mTreeView.setOnItemLongClickListener(new ExpandableListView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(
getActivity(),
position + " OnItemLongClickListener" + " Parent => " + ((RuleTreeItem) parent.getSelectedItem()).mName, Toast.LENGTH_SHORT)
.show();
// mSelectedTreeItem = XXX
//TODO - TA: set parent as mSelectedTreeItem
// openOperationBuilderDialog(-1, mSelectedTreeItem);
return false;
}
});
mRuleNameView.setText(((RuleEditActivity) getActivity()).getRuleName());
TextWatcher ruleNameTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
Log.d(HABApplication.getLogTag(), "ruleNameTextWatcher.afterTextChanged = " + s.toString());
((RuleEditActivity)getActivity()).setRuleName(s.toString());
}
};
mRuleNameView.addTextChangedListener(ruleNameTextWatcher);
setHasOptionsMenu(true);
RuleOperation initialRootOperation = null/*getInitialTreeOperation()*/;//TODO - TA: getInitialTreeOperation is just a time saver for UI test
((RuleEditActivity)getActivity()).getRule().setRuleOperation(initialRootOperation);
//TODO - TA: getInitialTreeOperation is just a time saver for UI test
// prepareMockedListData();
// prepareListData(initialRootOperation);
// mTreeListAdapter.notifyDataSetChanged();
// mTreeListAdapter.notifyDataSetInvalidated();
// updateRuleTree(initialRootOperation);
//-----------------------------------------
return view;
}
@Override
public void onStart() {
super.onStart();
Log.d("LifeCycle", "RuleOperationFragment.onStart()");
}
@Override
public void onResume() {
super.onResume();
Log.d("LifeCycle", "RuleOperationFragment.onResume()");
}
@Override
public void onPause() {
super.onPause();
Log.d("LifeCycle", "RuleOperationFragment.onPause()");
}
@Override
public void onStop() {
super.onStop();
Log.d("LifeCycle", "RuleOperationFragment.onStop()");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d("LifeCycle", "RuleOperationFragment.onDestroyView()");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("LifeCycle", "RuleOperationFragment.onDestroy()");
}
public void onUpdateView() {
if(mRuleNameView != null)
mRuleNameView.setText(((RuleEditActivity)getActivity()).getRuleName());
}
// // TODO: Rename method, update argument and hook method into UI event
// public void onButtonPressed(Uri uri) {
// if (mListener != null) {
// mListener.onFragmentInteraction(uri);
// }
// }
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d("LifeCycle", "RuleOperationFragment.onAttach()");
// try {
// mListener = (OnFragmentInteractionListener) activity;
// } catch (ClassCastException e) {
// throw new ClassCastException(activity.toString()
// + " must implement OnFragmentInteractionListener");
// }
}
@Override
public void onDetach() {
super.onDetach();
Log.d("LifeCycle", "RuleOperationFragment.onDetach()");
// mListener = null;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.rule_operation_edit, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit_rule_operation_member:
openOperationBuilderDialog(-1, mSelectedTreeItem);
break;
case R.id.action_delete_rule_operation_member:
//TODO - TA: Implement this.
Toast.makeText(getActivity(), "Not implemented", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
public void updateRuleTree(RuleOperation ruleOperationRoot) {
if(mTreeData == null)
mTreeData = new SparseArray<RuleTreeItem>();
mTreeData.clear();
if(ruleOperationRoot != null)
mTreeData.put(0, ruleOperationRoot.getRuleTreeItem(0));
mTreeListAdapter.notifyDataSetInvalidated();
}
public RuleTreeItem getSelectedTreeItem() {
return mSelectedTreeItem;
}
public void addTreeItem(IEntityDataType operand) {
getSelectedTreeItem().mChildren.put(getSelectedTreeItem().mChildren.size(), operand.getRuleTreeItem(getSelectedTreeItem().mChildren.size()));
mTreeListAdapter.notifyDataSetChanged();
mTreeListAdapter.notifyDataSetInvalidated();
}
public void addTreeItem(Integer treeIndex, RuleTreeItem ruleTreeItem) {
mTreeData.put(treeIndex, ruleTreeItem);
mTreeListAdapter.notifyDataSetChanged();
mTreeListAdapter.notifyDataSetInvalidated();
}
@Override
public void onOperationBuildResult(IRuleOperationBuildListener.RuleOperationSelectionInterface ruleOperationSelectionInterface
, IRuleOperationBuildListener.RuleOperationDialogButtonInterface ruleOperationDialogButtonInterface, IEntityDataType operand
, int operandPosition, RuleOperator ruleOperator) {
if(ruleOperationDialogButtonInterface == IRuleOperationBuildListener.RuleOperationDialogButtonInterface.CANCEL) {
if(mOperationUnderConstruction != null)
mOperationUnderConstruction.setActive(true);
return;
}
switch(ruleOperationSelectionInterface) {
case NA:
break;
case UNIT:
if (getSelectedTreeItem() != null) {
//Edit selected operation
mOperationUnderConstruction = ((RuleEditActivity)getActivity()).getOperationByOperandSourceId(operand.getDataSourceId());
} else {
//Create new operation
if(mOperationUnderConstruction == null)
mOperationUnderConstruction = new RuleOperation(/*"My operation"*/);
}
IEntityDataType oldOperand = mOperationUnderConstruction.getOperand(operandPosition);
if(oldOperand != null && oldOperand.getSourceType() == EntityDataTypeSource.UNIT)
mWidgetProvider.removeItemListener((UnitEntityDataType)oldOperand);
mOperationUnderConstruction.setOperand(operandPosition, operand);
if(operand != null)
mWidgetProvider.addItemListener((UnitEntityDataType) operand);
if(ruleOperationDialogButtonInterface == IRuleOperationBuildListener.RuleOperationDialogButtonInterface.NEXT)
openNewDialogAfterOperandSelection(operandPosition, operand);
break;
case NEW_OPERATION:
case EXISTING_OPERATION:
case STATIC:
if(mOperationUnderConstruction == null)
mOperationUnderConstruction = new RuleOperation(/*"My operation"*/);
mOperationUnderConstruction.setOperand(operandPosition, operand);
if(ruleOperationDialogButtonInterface == IRuleOperationBuildListener.RuleOperationDialogButtonInterface.NEXT)
openNewDialogAfterOperandSelection(operandPosition, operand);
break;
case OPERATOR:
RuleOperation currentOperation;
if (getSelectedTreeItem() != null) {
currentOperation = ((RuleEditActivity)getActivity()).getOperationByOperandSourceId(getSelectedTreeItem().getItemId());
} else {
currentOperation = mOperationUnderConstruction;
}
currentOperation.setRuleOperator(ruleOperator);
if(ruleOperationDialogButtonInterface == IRuleOperationBuildListener.RuleOperationDialogButtonInterface.NEXT) {
openOperationBuilderDialog(operandPosition + 1, mSelectedTreeItem);
return;
}
break;
}
if(ruleOperationDialogButtonInterface == IRuleOperationBuildListener.RuleOperationDialogButtonInterface.DONE) {
((RuleEditActivity)getActivity()).getRule().setRuleOperation(mOperationUnderConstruction);
mOperationUnderConstruction.setActive(true);
mOperationUnderConstruction.runCalculation();
updateRuleTree(mOperationUnderConstruction);
}
}
private void openNewDialogAfterOperandSelection(int previousOperandPosition, IEntityDataType operand) {
if(previousOperandPosition == 0) {
final List<String> operatorList = mAdapterProvider.getRuleOperatorList(getActivity(),
operand,
false);
final OperatorSelectionDialogFragment dialogFragment = OperatorSelectionDialogFragment.newInstance(operand.getDataSourceId(),
operand.getSourceType(),
"Select an operator",
true,
operatorList);
dialogFragment.show(getFragmentManager(), "String_Selection_Dialog_Tag");
} else if(mOperationUnderConstruction.getRuleOperator() != null && mOperationUnderConstruction.getRuleOperator().supportsMultipleOperations()) {
openRuleOperandDialogFragment(mOperationUnderConstruction.getOperand(previousOperandPosition + 1), previousOperandPosition + 1, true);
}
}
public void openRuleOperandDialogFragment(IEntityDataType currentOperand, int position, boolean showNextButton) {
((RuleEditActivity)getActivity()).setOperandToEdit(currentOperand);
final RuleOperandDialogFragment dialogFragment = RuleOperandDialogFragment.newInstance(
position != -1 ? position : 0, showNextButton);
dialogFragment.show(getFragmentManager(), "Operation_Builder_Tag");
}
public void openOperationBuilderDialog(int aOperandposition, RuleTreeItem selectedTreeItem) {
RuleTreeItem rti = selectedTreeItem;
if (rti == null && ((RuleEditActivity)getActivity()).getRule().getRuleOperation() != null) {
Toast.makeText(getActivity(), "Select a target item first.", Toast.LENGTH_SHORT).show();
} else if (rti == null || rti.getItemType() == RuleTreeItem.ItemType.OPERAND) {
if(rti == null && mOperationUnderConstruction == null && ((RuleEditActivity)getActivity()).getRule().getRuleOperation() == null) {
((RuleEditActivity)getActivity()).setOperandToEdit(null);
final RuleOperandDialogFragment dialogFragment = RuleOperandDialogFragment.newInstance(0, true);
dialogFragment.show(getFragmentManager(), "Operation_Builder_Tag");
return;
}/* else
rti = mRule.getRuleOperation().getRuleTreeItem();*///TODO - TA: get current operation and open it up
mOperationUnderConstruction = rti != null? ((RuleEditActivity)getActivity()).getOperationByOperandSourceId(rti.getItemId()) : mOperationUnderConstruction;
int operandPosition = aOperandposition;
if(operandPosition == -1 && mOperationUnderConstruction.getSourceType() != EntityDataTypeSource.OPERATION) {
operandPosition = rti.getPosition();
} else if(operandPosition == -1) {
operandPosition = 0;
}
((RuleEditActivity)getActivity()).setOperationToEdit(mOperationUnderConstruction);
mOperationUnderConstruction.setActive(false);
((RuleEditActivity)getActivity()).setOperandToEdit(mOperationUnderConstruction.getOperand(operandPosition));
final RuleOperandDialogFragment dialogFragment = RuleOperandDialogFragment.newInstance(
operandPosition != -1 ? operandPosition : 0
, operandPosition < 1
|| (operandPosition > 1 && (mOperationUnderConstruction.getRuleOperator() != null
&& mOperationUnderConstruction.getRuleOperator().supportsMultipleOperations())
)
);
dialogFragment.show(getFragmentManager(), "Operation_Builder_Tag");
} else if (rti.getItemType() == RuleTreeItem.ItemType.OPERATOR) {
//TODO - TA: open an operator selection dialog.
((RuleEditActivity)getActivity()).getOperatorBySourceId(rti.getItemId());
}
}
//==============================================================
// T E S T
//==============================================================
/*
* Preparing the list data
*/
private RuleOperation getInitialTreeOperation() {
List<IEntityDataType> operandList = new ArrayList<IEntityDataType>();
operandList.add(getRuleOperation());
operandList.add(getRuleOperation());
RuleOperator ror = mRuleOperationProvider.getRuleOperator(Boolean.class, RuleOperatorType.And);
RuleOperation ron = new RuleOperation(ror, operandList);
ron.setName("The is the name of the root operation.");
// prepareMockedListData();//TODO - TA: getInitialTreeOperation is just a time saver for UI test
// prepareListData(ron);//TODO - TA: getInitialTreeOperation is just a time saver for UI test
return ron;
}
private void prepareListData(RuleOperation ruleOperationRoot) {
// Adding tree data
List<IEntityDataType> operandList = new ArrayList<IEntityDataType>();
operandList.add(getRuleOperation());
operandList.add(getRuleOperation());
RuleOperator ror = mRuleOperationProvider.getRuleOperator(Boolean.class, RuleOperatorType.And);
RuleOperation ron2 = new RuleOperation(ror, operandList);
RuleOperation ron3 = new RuleOperation(ror, operandList);
ron3.setName("The is the name of the ron3 rule.");
if(mTreeData == null)
mTreeData = new SparseArray<RuleTreeItem>();
mTreeData.put(0, ron2.getRuleTreeItem(0));
mTreeData.put(1, ron3.getRuleTreeItem(1));
((RuleEditActivity)getActivity()).getRule().setRuleOperation(ron3);
}
/*
* Preparing the list data
*/
private void prepareMockedListData() {
// Adding child data
HashMap<Integer, RuleTreeItem> top250 = new HashMap<Integer, RuleTreeItem>();
top250.put(0, new RuleTreeItem(0, "The Shawshank Redemption", RuleTreeItem.ItemType.OPERAND));
top250.put(1, new RuleTreeItem(1, "The Godfather", RuleTreeItem.ItemType.OPERAND));
top250.put(2, new RuleTreeItem(2, "The Godfather: Part II", RuleTreeItem.ItemType.OPERAND));
top250.put(3, new RuleTreeItem(3, "Pulp Fiction", RuleTreeItem.ItemType.OPERAND));
top250.put(4, new RuleTreeItem(4, "The Good, the Bad and the Ugly", RuleTreeItem.ItemType.OPERAND));
top250.put(5, new RuleTreeItem(5, "The Dark Knight", RuleTreeItem.ItemType.OPERAND));
top250.put(6, new RuleTreeItem(6, "12 Angry Men", RuleTreeItem.ItemType.OPERAND));
HashMap<Integer, RuleTreeItem> thirdLevel = new HashMap<Integer, RuleTreeItem>();
thirdLevel.put(0, new RuleTreeItem(0, "Närkontakt", RuleTreeItem.ItemType.OPERAND));
thirdLevel.put(1, new RuleTreeItem(1, "Av tredje", RuleTreeItem.ItemType.OPERAND));
thirdLevel.put(2, new RuleTreeItem(2, "Graden", RuleTreeItem.ItemType.OPERAND));
HashMap<Integer, RuleTreeItem> nowShowing = new HashMap<Integer, RuleTreeItem>();
nowShowing.put(0, new RuleTreeItem(0, "The Conjuring", RuleTreeItem.ItemType.OPERAND));
nowShowing.put(1, new RuleTreeItem(1, "Despicable Me 2", RuleTreeItem.ItemType.OPERAND));
nowShowing.put(2, new RuleTreeItem(2, "Turbo", RuleTreeItem.ItemType.OPERAND));
nowShowing.put(3, new RuleTreeItem(3, "Grown Ups 2", RuleTreeItem.ItemType.OPERAND, thirdLevel));
nowShowing.put(4, new RuleTreeItem(4, "Red 2", RuleTreeItem.ItemType.OPERAND));
nowShowing.put(5, new RuleTreeItem(5, "The Wolverine", RuleTreeItem.ItemType.OPERAND));
HashMap<Integer, RuleTreeItem> comingSoon = new HashMap<Integer, RuleTreeItem>();
List<IEntityDataType> operandList = new ArrayList<IEntityDataType>();
operandList.add(getRuleOperation());
operandList.add(getRuleOperation());
RuleOperator ror = mRuleOperationProvider.getRuleOperator(Boolean.class, RuleOperatorType.And);
RuleOperation ron2 = new RuleOperation(ror, operandList);
RuleOperation ron3 = new RuleOperation(ror, operandList);
ron3.setName("The is the name of the ron3 rule.");
comingSoon.put(0, new RuleTreeItem(0, "Men In Black", RuleTreeItem.ItemType.OPERAND));
comingSoon.put(1, ron2.getRuleTreeItem(1));
comingSoon.put(2, new RuleTreeItem(2, "The Spectacular Now", RuleTreeItem.ItemType.OPERAND));
comingSoon.put(3, ron3.getRuleTreeItem(3));
comingSoon.put(4, new RuleTreeItem(4, "Europa Report", RuleTreeItem.ItemType.OPERAND));
comingSoon.put(5, new RuleTreeItem(5, "Apocalypse Now", RuleTreeItem.ItemType.OPERAND));
if(mTreeData == null)
mTreeData = new SparseArray<RuleTreeItem>();
mTreeData.put(0, new RuleTreeItem(0, "Top 250", RuleTreeItem.ItemType.OPERAND, top250));
mTreeData.put(1, new RuleTreeItem(1, "Now Showing", RuleTreeItem.ItemType.OPERAND, nowShowing));
mTreeData.put(2, new RuleTreeItem(2, "Coming Soon...", RuleTreeItem.ItemType.OPERAND, comingSoon));
}
private RuleOperation getRuleOperation() {
final HABApplication application = (HABApplication) getActivity().getApplication();
OpenHABWidget widget = mWidgetProvider.getWidgetByID("FF_Child_2");
return new RuleOperation(mRuleOperationProvider.getRuleOperator(widget, RuleOperatorType.Equal), getOperandsAsList3(2));
}
private List<IEntityDataType> getOperandsAsList3(int operandPairNumber) {
List<IEntityDataType> operands = new ArrayList<IEntityDataType>();
switch(operandPairNumber) {
case 1:
//Switch
operands.add(mUnitEntityDataTypeProvider.getUnitEntityDataType(mWidgetProvider.getWidgetByID("GF_Toilet_1")));
operands.add(mUnitEntityDataTypeProvider.getUnitEntityDataType(mWidgetProvider.getWidgetByID("GF_Corridor_1")));
break;
case 2:
//Number
operands.add(mUnitEntityDataTypeProvider.getUnitEntityDataType(mWidgetProvider.getWidgetByID("FF_Child_2")));//"demo_1_0"
operands.add(mUnitEntityDataTypeProvider.getUnitEntityDataType(mWidgetProvider.getWidgetByID("FF_Bath_4")));//ekafallettest_1
break;
}
return operands;
}
}