content: /*
   * Copyright 2011, Institute of Cybernetics at Tallinn University of Technology
   *
   * 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 com.alexvt.whisperinput.speak.provider;
  
  import java.util.HashMap;
  
  import com.alexvt.whisperinput.speak.Log;
  import com.alexvt.whisperinput.R;
  
  import android.content.ContentProvider;
  import android.content.ContentUris;
  import android.content.ContentValues;
  import android.content.Context;
  import android.content.UriMatcher;
  import android.database.Cursor;
  import android.database.SQLException;
  import android.database.sqlite.SQLiteDatabase;
  import android.database.sqlite.SQLiteOpenHelper;
  import android.database.sqlite.SQLiteQueryBuilder;
  import android.net.Uri;
  import android.text.TextUtils;
  
  // TODO: rename to SpeakContentProvider (or ContentProvider)
  public class AppsContentProvider extends ContentProvider {
  
  	public static final String APPS_TABLE_NAME = "apps";
  	public static final String GRAMMARS_TABLE_NAME = "grammars";
  	public static final String SERVERS_TABLE_NAME = "servers";
  
  	public static final String AUTHORITY = "com.alexvt.whisperinput.speak.provider.AppsContentProvider";
  
  	private static final String TAG = "AppsContentProvider";
  
  	private static final String DATABASE_NAME = "speak.db";
  
  	private static final int DATABASE_VERSION = 3;
  
  	private static final UriMatcher sUriMatcher;
  
  	private static final int APPS = 1;
  	private static final int APP_ID = 2;
  	private static final int GRAMMARS = 3;
  	private static final int GRAMMAR_ID = 4;
  	private static final int SERVERS = 5;
  	private static final int SERVER_ID = 6;
  
  	private static HashMap<String, String> appsProjectionMap;
  	private static HashMap<String, String> grammarsProjectionMap;
  	private static HashMap<String, String> serversProjectionMap;
  
  	private DatabaseHelper dbHelper;
  
  	private static class DatabaseHelper extends SQLiteOpenHelper {
  
  		private final Context mContext;
  
  		DatabaseHelper(Context context) {
  			super(context, DATABASE_NAME, null, DATABASE_VERSION);
  			mContext = context;
  		}
  
  		/**
  		 * GRAMMAR and SERVER should be a foreign keys
  		 * Grammar should have language ID
  		 */
  		@Override
  		public void onCreate(SQLiteDatabase db) {
  			db.execSQL("CREATE TABLE " + APPS_TABLE_NAME + " ("
  					+ App.Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  					+ App.Columns.FNAME + " TEXT NOT NULL,"
  					+ App.Columns.GRAMMAR + " INTEGER,"
  					+ App.Columns.SERVER + " INTEGER,"
  					+ App.Columns.COUNT + " INTEGER,"
  					+ "UNIQUE(" + App.Columns.FNAME + ") ON CONFLICT REPLACE"
  					+ ");");
  
  			db.execSQL("CREATE TABLE " + GRAMMARS_TABLE_NAME + " ("
  					+ Grammar.Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  					+ Grammar.Columns.NAME + " VARCHAR(255),"
  					+ Grammar.Columns.DESC + " TEXT,"
  					+ Grammar.Columns.LANG + " VARCHAR(255),"
  					+ Grammar.Columns.URL + " TEXT NOT NULL,"
  					+ "UNIQUE(" + Grammar.Columns.URL + "," + Grammar.Columns.LANG + ") ON CONFLICT REPLACE"
  					+ ");");
  
  			db.execSQL("CREATE TABLE " + SERVERS_TABLE_NAME + " ("
  					+ Server.Columns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  					+ Server.Columns.URL + " TEXT NOT NULL,"
  					+ "UNIQUE(" + Server.Columns.URL + ") ON CONFLICT REPLACE"
  					+ ");");
  
  			// TODO: check that the default service name does not contain any apostrophes
  			db.execSQL("INSERT INTO " + SERVERS_TABLE_NAME + " VALUES (" +
  					"'1', " +
  					"'" +
  					mContext.getString(R.string.defaultHttpServer) +
  					"'" + ");");
  
  			// Predefined grammar URLs
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'1', " +
  					"'" + mContext.getString(R.string.entryGrammarName1) + "', " +
  					"'" + mContext.getString(R.string.entryGrammarDesc1) + "', " +
  					"'', " +
  					"''" +
  					");");
  
  			// TODO: externalize all these strings
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'2', " +
  					"'Go', " +
  					"'Väike näitegrammatika, nt ''mine kolm meetrit edasi'', ''mine neli meetrit tagasi''', " +
  					"'Eng', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Go.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'3', " +
  					"'Expr (left-associative)', " +
  					"'Aritmeetilised avaldised, nt ''miinus kaks pluss kolm koma neli korda viis''', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Expr.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'4', " +
  					"'Unitconv', " +
  					"'Mõõtude teisendamine, nt ''kaksteist ruutjalga ruutkilomeetrites''', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Unitconv.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'5', " +
  					"'Action', " +
  					"'Alarm + Calc + Direction', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Action.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'6', " +
  					"'Direction', " +
  					"'Eesti aadressid, nt ''Algus Pariisi Lõpp Sõpruse puiestee kakssada kolmteist Tallinn''', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Direction.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'7', " +
  					"'Calc', " +
  					"'Expr + Unitconv', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Calc.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'8', " +
  					"'Symbols', " +
  					"'Suvalise pikkusega numbrite ja tähtede jada', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Symbols.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'9', " +
  					"'Estvrp', " +
  					"'Eesti autonumbrimärgi keel, nt ''aaa bee tsee üks kaks kolm''', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Estvrp.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'10', " +
  					"'Direction (Tallinn)', " +
  					"'Keel ''Direction'' alamhulk, mis katab ainult Tallinna', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Tallinndirection.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'11', " +
  					"'Direction (Tallinn)', " +
  					"'Keel ''Direction'' alamhulk, mis katab ainult Tallinna', " +
  					"'Edwin', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Tallinndirection.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'12', " +
  					"'Go', " +
  					"'Väike näitegrammatika, nt ''mine kolm meetrit edasi'', ''mine neli meetrit tagasi''', " +
  					"NULL, " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Go.pgf'" +
  					");");
  
  			db.execSQL("INSERT INTO " + GRAMMARS_TABLE_NAME + " VALUES (" +
  					"'13', " +
  					"'Alarm', " +
  					"'Nt ''ärata mind kell kaheksa null üks''', " +
  					"'App', " +
  					"'http://kaljurand.github.com/Grammars/grammars/pgf/Alarm.pgf'" +
  					");");
  		}
  
  
  		@Override
  		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  			Log.i(TAG, "Upgrading database v" + oldVersion + " -> v" + newVersion + ", which will destroy all old data.");
  			db.execSQL("DROP TABLE IF EXISTS " + APPS_TABLE_NAME);
  			db.execSQL("DROP TABLE IF EXISTS " + GRAMMARS_TABLE_NAME);
  			db.execSQL("DROP TABLE IF EXISTS " + SERVERS_TABLE_NAME);
  			onCreate(db);
  		}
  	}
  
  	@Override
  	public int delete(Uri uri, String where, String[] whereArgs) {
  		SQLiteDatabase db = dbHelper.getWritableDatabase();
  		int count;
  		switch (sUriMatcher.match(uri)) {
  		case APPS:
  			count = db.delete(APPS_TABLE_NAME, where, whereArgs);
  			break;
  
  		case APP_ID:
  			String appId = uri.getPathSegments().get(1);
  			count = db.delete(
  					APPS_TABLE_NAME,
  					App.Columns._ID + "=" + appId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
  					whereArgs);
  			break;
  
  		case GRAMMARS:
  			count = db.delete(GRAMMARS_TABLE_NAME, where, whereArgs);
  			break;
  
  		case GRAMMAR_ID:
  			String grammarId = uri.getPathSegments().get(1);
  			count = db.delete(
  					GRAMMARS_TABLE_NAME,
  					Grammar.Columns._ID + "=" + grammarId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
  					whereArgs);
  			break;
  
  		case SERVERS:
  			count = db.delete(SERVERS_TABLE_NAME, where, whereArgs);
  			break;
  
  		case SERVER_ID:
  			String serverId = uri.getPathSegments().get(1);
  			count = db.delete(
  					SERVERS_TABLE_NAME,
  					Server.Columns._ID + "=" + serverId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
  					whereArgs);
  			break;
  
  
  		default:
  			throw new IllegalArgumentException("Unknown URI " + uri);
  		}
  
  		getContext().getContentResolver().notifyChange(uri, null);
  		return count;
  	}
  
  
  	@Override
  	public String getType(Uri uri) {
  		switch (sUriMatcher.match(uri)) {
  		case APPS:
  			return App.Columns.CONTENT_TYPE;
  		case GRAMMARS:
  			return Grammar.Columns.CONTENT_TYPE;
  		case SERVERS:
  			return Server.Columns.CONTENT_TYPE;
  
  		default:
  			throw new IllegalArgumentException("Unknown URI " + uri);
  		}
  	}
  
  
  	@Override
  	public Uri insert(Uri uri, ContentValues initialValues) {
  		ContentValues values;
  		if (initialValues != null) {
  			values = new ContentValues(initialValues);
  		} else {
  			values = new ContentValues();
  		}
  
  		SQLiteDatabase db = dbHelper.getWritableDatabase();
  		long rowId = 0;
  		Uri returnUri = null;
  
  		switch (sUriMatcher.match(uri)) {
  		case APPS:
  			rowId = db.insert(APPS_TABLE_NAME, App.Columns.FNAME, values);
  			if (rowId <= 0) {
  				throw new SQLException("Failed to insert row into " + uri);
  			}
  			returnUri = ContentUris.withAppendedId(App.Columns.CONTENT_URI, rowId);
  			getContext().getContentResolver().notifyChange(returnUri, null);
  			return returnUri;
  
  		case GRAMMARS:
  			rowId = db.insert(GRAMMARS_TABLE_NAME, Grammar.Columns.DESC, values);
  			if (rowId <= 0) {
  				throw new SQLException("Failed to insert row into " + uri);
  			}
  			returnUri = ContentUris.withAppendedId(Grammar.Columns.CONTENT_URI, rowId);
  			getContext().getContentResolver().notifyChange(returnUri, null);
  			return returnUri;
  
  		case SERVERS:
  			rowId = db.insert(SERVERS_TABLE_NAME, Server.Columns.URL, values);
  			if (rowId <= 0) {
  				throw new SQLException("Failed to insert row into " + uri);
  			}
  			returnUri = ContentUris.withAppendedId(Server.Columns.CONTENT_URI, rowId);
  			getContext().getContentResolver().notifyChange(returnUri, null);
  			return returnUri;
  
  		default:
  			throw new IllegalArgumentException("Unknown URI " + uri);
  		}
  	}
  
  
  	@Override
  	public boolean onCreate() {
  		dbHelper = new DatabaseHelper(getContext());
  		return true;
  	}
  
  
  	@Override
  	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
  
  		switch (sUriMatcher.match(uri)) {
  		case APPS:
  			qb.setTables(APPS_TABLE_NAME);
  			qb.setProjectionMap(appsProjectionMap);
  			break;
  		case GRAMMARS:
  			qb.setTables(GRAMMARS_TABLE_NAME);
  			qb.setProjectionMap(grammarsProjectionMap);
  			break;
  		case SERVERS:
  			qb.setTables(SERVERS_TABLE_NAME);
  			qb.setProjectionMap(serversProjectionMap);
  			break;
  
  		default:
  			throw new IllegalArgumentException("Unknown URI " + uri);
  		}
  
  		SQLiteDatabase db = dbHelper.getReadableDatabase();
  		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
  
  		c.setNotificationUri(getContext().getContentResolver(), uri);
  		return c;
  	}
  
  
  	@Override
  	public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
  		SQLiteDatabase db = dbHelper.getWritableDatabase();
  		int count;
  		switch (sUriMatcher.match(uri)) {
  		case APPS:
  			count = db.update(APPS_TABLE_NAME, values, where, whereArgs);
  			break;
  
  		case GRAMMARS:
  			count = db.update(GRAMMARS_TABLE_NAME, values, where, whereArgs);
  			break;
  
  		case SERVERS:
  			count = db.update(SERVERS_TABLE_NAME, values, where, whereArgs);
  			break;
  
  		case APP_ID:
  			String appId = uri.getPathSegments().get(1);
  			count = db.update(
  					APPS_TABLE_NAME,
  					values,
  					App.Columns._ID + "=" + appId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
  					whereArgs);
  			break;
  
  		case GRAMMAR_ID:
  			String grammarId = uri.getPathSegments().get(1);
  			count = db.update(
  					GRAMMARS_TABLE_NAME,
  					values,
  					Grammar.Columns._ID + "=" + grammarId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
  					whereArgs);
  			break;
  
  		case SERVER_ID:
  			String serverId = uri.getPathSegments().get(1);
  			count = db.update(
  					SERVERS_TABLE_NAME,
  					values,
  					Server.Columns._ID + "=" + serverId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""),
  					whereArgs);
  			break;
  
  		default:
  			throw new IllegalArgumentException("Unknown URI " + uri);
  		}
  
  		getContext().getContentResolver().notifyChange(uri, null);
  		return count;
  	}
  
  	static {
  		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  		sUriMatcher.addURI(AUTHORITY, APPS_TABLE_NAME, APPS);
  		sUriMatcher.addURI(AUTHORITY, APPS_TABLE_NAME + "/#", APP_ID);
  		sUriMatcher.addURI(AUTHORITY, GRAMMARS_TABLE_NAME, GRAMMARS);
  		sUriMatcher.addURI(AUTHORITY, GRAMMARS_TABLE_NAME + "/#", GRAMMAR_ID);
  		sUriMatcher.addURI(AUTHORITY, SERVERS_TABLE_NAME, SERVERS);
  		sUriMatcher.addURI(AUTHORITY, SERVERS_TABLE_NAME + "/#", SERVER_ID);
  
  		appsProjectionMap = new HashMap<>();
  		appsProjectionMap.put(App.Columns._ID, App.Columns._ID);
  		appsProjectionMap.put(App.Columns.FNAME, App.Columns.FNAME);
  		appsProjectionMap.put(App.Columns.GRAMMAR, App.Columns.GRAMMAR);
  		appsProjectionMap.put(App.Columns.SERVER, App.Columns.SERVER);
  		appsProjectionMap.put(App.Columns.COUNT, App.Columns.COUNT);
  
  		grammarsProjectionMap = new HashMap<>();
  		grammarsProjectionMap.put(Grammar.Columns._ID, Grammar.Columns._ID);
  		grammarsProjectionMap.put(Grammar.Columns.NAME, Grammar.Columns.NAME);
  		grammarsProjectionMap.put(Grammar.Columns.LANG, Grammar.Columns.LANG);
  		grammarsProjectionMap.put(Grammar.Columns.DESC, Grammar.Columns.DESC);
  		grammarsProjectionMap.put(Grammar.Columns.URL, Grammar.Columns.URL);
  
  		serversProjectionMap = new HashMap<>();
  		serversProjectionMap.put(Server.Columns._ID, Server.Columns._ID);
  		serversProjectionMap.put(Server.Columns.URL, Server.Columns.URL);
  
  	}
  }