package net.bradmont.supergreen.fields;
import net.bradmont.supergreen.models.DBModel;
import net.bradmont.supergreen.fields.constraints.*;
import java.util.List;
import java.util.LinkedList;
import java.util.Date;
import java.util.Calendar;
import android.database.Cursor;
import android.widget.*;
import android.util.Log;
import android.view.View;
public abstract class DBField {
private String name; // field name
private String column_name = null;
protected String extra_arguments = null;
boolean has_default = false;
DBModel ownerModel = null;
Constraint [] constraints = null;
/**
* Creates a new, blank DBField instance.
*/
public DBField(String name){
this.name=name;
}
/**
* Add Constraints to a field for data validation.
*/
public void addConstraints(Constraint ... constraints){
this.constraints = new Constraint[constraints.length];
for (int i = 0; i < constraints.length; i++){
this.constraints[i] = constraints[i];
}
}
public boolean validate() throws ConstraintError{
if (constraints == null){
return true;
}
for (int i = 0; i < constraints.length; i++){
constraints[i].validate(this);
}
return true;
}
public abstract void putToView(View v);
public abstract void getFromView(View v) throws ConstraintError;
public void setColumnName(String column_name){
this.column_name=column_name;
ownerModel.setFieldColumnName(getName(), column_name);
}
/**
* Add extra arguments to the field's table definition SQL, such as
* AUTOINCREMENT, NOT NULL, etc.
*/
public void setExtraArguments(String extra_arguments){
this.extra_arguments = extra_arguments;
}
public String getExtraArguments(){
return extra_arguments;
}
public String getColumnName(){
if (column_name == null){
return name;
} else {
return column_name;
}
}
public String getName(){
return name;
}
protected String viewToString(View v){
String value = "";
if (v instanceof EditText){
value = ((EditText) v).getText().toString();
} else if (v instanceof Switch){
value = ((Switch) v).isChecked()? "1" : "0";
} else if (v instanceof CheckBox){
value = ((CheckBox) v).isChecked()? "1" : "0";
} else if (v instanceof ToggleButton){
value = ((ToggleButton) v).isChecked()? "1" : "0";
} else if (v instanceof Spinner){
// we can deal with ArrayAdapter spinners easily enough,
// but further detail is required for CursorAdapters or others
SpinnerAdapter sa = ((Spinner) v).getAdapter();
if (sa instanceof ArrayAdapter){
value = ((Spinner) v).getSelectedItem().toString();
} else {
value = getSpinnerValue((Spinner) v);
}
} else if (v instanceof TextView){
value = ((TextView) v).getText().toString();
}
//Log.i("net.bradmont.supergreen", "getFromView value " + value);
return value;
}
protected void stringToView(View v, String value){
if (v == null){
// don't do anything if the voew doesn't have this field
return;
} else if (v instanceof EditText){
((EditText) v).setText(value);
} else if (v instanceof Switch){
((Switch) v).setChecked(value.equals("1"));
} else if (v instanceof CheckBox){
((CheckBox) v).setChecked(value.equals("1"));
} else if (v instanceof ToggleButton){
((ToggleButton) v).setChecked(value.equals("1"));
} else if (v instanceof Spinner){
setSpinnerPosition((Spinner) v);
SpinnerAdapter sa = ((Spinner) v).getAdapter();
if (((Spinner)v).getSelectedItemPosition() == 0 && sa instanceof ArrayAdapter){
// if it's an ArrayAdapter, and it looks like setSpinnerPosition
// might not be implemented, we can try to implement some basic
// functionality here. If setSpinnerPosition worked and selected
// item 0, no harm done.
int spinnerPosition = ((ArrayAdapter) sa).getPosition(value);
((Spinner) v).setSelection(spinnerPosition);
}
} else if (v instanceof TextView){
((TextView) v).setText(value);
}
}
protected String getSpinnerValue(Spinner s){
// override for intelligent selection
Object val = s.getSelectedItem();
if (val instanceof Cursor){
return ((Cursor)val).getString(0);
}
return s.getSelectedItem().toString();
}
/**
* When populating a spinner from an existing DBField, this function
* should select the appropirate Spinner item; if you're using a
* SpinnerAdapterother than a simpe ArrayAdapter of string values, you
* must build your own subclass of the apropriate DBField type and
* override this method.
* @param s The spinner to populate
*/
protected void setSpinnerPosition(Spinner s){
// override for intelligent selection
s.setSelection(0);
}
public void setModel(DBModel model){
ownerModel = model;
}
/**
* Get a reference to the DBModel of which this field is a member
*/
public DBModel getModel(){
return ownerModel;
}
/**
* Get a reference to another field of the DBModel of which this field is a member.
*/
public DBField getField(String name){
return ownerModel.getField(name);
}
public int getInt(){
throw (new NotImplementedException("getInt"));
}
public String getString(){
throw (new NotImplementedException("getString"));
}
public float getFloat(){
throw (new NotImplementedException("getFloat"));
}
public boolean getBoolean(){
throw (new NotImplementedException("getBoolean"));
}
public Calendar getCalendar(){
throw (new NotImplementedException("getInt"));
}
public DBModel getRelated(){
throw (new NotImplementedException("getRelated"));
}
/**
* Generate SQL definition for the field's data, for CREATE
* and UPDATE queries. Must be overriden for each subclass.
*/
public String getSQLDefinition(){
throw (new NotImplementedException("getSQLDefinition"));
// TODO: process constraints
}
/**
* Generate SQL definition for the field's related table
* constraints, eg, to create foreign keys. Override when
* a field uses it.
*/
public String getSQLTableConstraint(){
return "";
}
/**
* Set a field's default value to an int, for supported fields.
*/
public void setDefault(int value){
setValue(value);
}
/**
* Set a field's default value to a String, for supported fields.
*/
public void setDefault(String value){
setValue(value);
}
/**
* Set a field's default value to a float, for supported fields.
*/
public void setDefault(float value){
setValue(value);
}
/**
* Set a field's default value to a boolean, for supported fields.
*/
public void setDefault(boolean value){
setValue(value);
}
/**
* Set a field's default value to a Date, for supported fields.
*/
public void setDefault(Calendar value){
setValue(value);
}
/**
* Set the value of a field to an int, for supported fields
*/
public void setValue(int value){
throw (new NotImplementedException("setValue(int)"));
}
/**
* Set the value of a field to a String, for supported fields
*/
public void setValue(String value){
throw (new NotImplementedException("setValue(String)"));
}
/**
* Set the value of a field to a Float, for supported fields
*/
public void setValue(float value){
throw (new NotImplementedException("setValue(Float)"));
}
/**
* Set the value of a field to a boolean, for supported fields
*/
public void setValue(boolean value){
throw (new NotImplementedException("setValue(boolean)"));
}
/**
* Set the value of a field to a related DBModel (foreign keys only)
*/
public void setValue(Calendar value){
throw (new NotImplementedException("setValue(Calendar)"));
}
public void setValue(DBModel value){
throw (new NotImplementedException("setValue(DBModel)"));
}
class NotImplementedException extends RuntimeException{
NotImplementedException(String message){
super(message);
}
}
}