package kz.istt.locust;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.webkit.URLUtil;

/*import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.CoreProtocolPNames;*/
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.ByteArrayOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.Semaphore;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import tctable.TCField;
import tctable.TCTable;
import tctable.TCTableTools;
import tools.TCTableTools2;

//import org.apache.http.entity.MultipartEntity;

/** Синхронизация данных с сервером
 * Нужно сделать глобальным
 * */
public class MySynchronizationOld
{
	public static String URL="https://ccalm.org";
	public static int SyncDays=30; // How many days to store data of sent data packets and synchronize with the server

	private Context _context; //От какого контекста показывать алерты
	private String android_id;
	//private boolean _showAlert; //Показывать ли окно подождите пожалуйста (его нельзя создавать если в сервисе)
	//public ProgressDialog dialog;

	public MyThread myThread = null;

/*
	private int rid_sendFrmLocust = -1; //Для отправки данных
	private int rid_sendFrmLocustDel = -1; //Для отправки данных
	private int rid_sendFrmLocustHealth = -1; //Для отправки данных

	//private int rid_frmlocust = -1; //Для запроса данных (не используется так как нет синхронизации)
	private int rid_frmlocustdel = -1; //Для запроса данных
	private int rid_frmlocustdel_locations = -1; //Для подгрузки координат формы

	private int rid_Borns = -1;
	private int rid_countries=-1; //Для идентификации прихода данных списка стран
	private int rid_CountriesRegions = -1; //Для идентификации прихода данных списка регионов
	private int rid__languages = -1;
	private int rid__translations = -1;
	//private int rid_LocustsTypes = -1; //Виды саранчи
	private int rid_list_density = -1;
	private int rid_list_directions = -1; //Стороны света (направления)
	private int rid_list_phase = -1;
	private int rid_sprayers = -1;
	private int rid_sprayers_types = -1;
	private int rid_Fledgling = -1; //Окрыление
	private int rid_list_damage = -1;
	private int rid_list_mortality = -1; //Метод подсчёта смертности (визуальный либо учётная рамка)
	private int rid_list_greenery = -1; //Состояние растительности
	private int rid_list_biotope = -1;
	private int rid_list_cover = -1;
	private int rid_list_age = -1;
	private int rid_list_actions = -1;
	private int rid_list_paintings = -1;
	private int rid_list_behaviors = -1;
	private int rid_list_breeding = -1;
	//int rid_list_operatorstypes = -1;
	private int rid_list_capacities = -1;
	private int rid_list_markings = -1;
	private int rid_list_containers = -1; //Что сделали с пустыми контейнерами от отравы
	private int rid_list_containers_states = -1;
	private int rid_list_vegetation = -1;
	private int rid_list_formulation = -1;
	private int rid_list_height = -1;
	private int rid_list_enemies = -1;
	private int rid_list_purpose = -1;
	private int rid_list_impact = -1;
	private int rid_list_diluted = -1;
	private int rid_terminals = -1; //На кого зарегистрирован данныей планшет
	private int rid_companies = -1;
*/
	MySynchronizationOld(Context context)
	{
		_context = context;
		loadURL();

		String appPath = _context.getApplicationContext().getFilesDir().getAbsolutePath();
		//Thread for downloading from Internet
		myThread = new MyThread(this, appPath);
		myThread.start(); //Стартуем поток
	}

	//Download setup from local storage
	public void loadURL()
	{
		String URL = MySynchronizationOld.URL;
		SharedPreferences prefs = _context.getSharedPreferences("CommonPrefs", Activity.MODE_PRIVATE);
		URL = prefs.getString("URL", "");
		MySynchronizationOld.SyncDays = prefs.getInt("SyncDays", MySynchronizationOld.SyncDays);
		if(URLUtil.isValidUrl(URL))
			MySynchronizationOld.URL = URL;
	}

	public void renameImage(String name){
		String path;
		File pFile;
		path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + name;
		pFile = new File(path);
		if (pFile.exists()) //Переименовываю файл чтобы заново не отправить при редактировании
		{
			pFile.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/_" + name));
		}
	}

	/*public static HttpClient getTestHttpClient() {
		try {
			SSLContextBuilder builder = new SSLContextBuilder();
			builder.loadTrustMaterial(null, new TrustStrategy() {
				@Override
				public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
					return true;
				}
			});
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier());
			CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			return httpclient;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	}*/

	public int getCount()
	{
		if(myThread!=null)
			return myThread.getCountTasks();
		else
			return 0;
	}

	/** Отправить анкету саранчи на сервер по идентификатору либо по времени создания (время должно быть уникальным)
	 * */
	public void sendFrmLocust(String uid)
	{
		if(uid==null || uid.equals("")) return;

		String xml="";
		DbOpenHelper dboh = new DbOpenHelper(_context);
		Cursor cursor = null;
		SQLiteDatabase rdb = null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select * from frmlocust where uid=?", new String[] { String.valueOf(uid) });

			if(cursor.moveToFirst())
			{
				do{
					//Если задано имя файла то добавляем его в очередь на отправку на сервер
					String fname;
					fname=cursor.getString(cursor.getColumnIndex("image_name1"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic1","xml",MySynchronizationOld.URL+"/get/?fn=6", null,null, Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);

					fname = cursor.getString(cursor.getColumnIndex("image_name2"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic2","xml",MySynchronizationOld.URL+"/get/?fn=6", null,null, Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);

					fname = cursor.getString(cursor.getColumnIndex("image_name3"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic2","xml",MySynchronizationOld.URL+"/get/?fn=6", null,null, Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);

					xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
					xml+="<metadata fn=\"4\">";
					for(int i=0;i<cursor.getColumnCount();i++)
					{
						String val="";
						if(!cursor.isNull(i)) {
							if (cursor.getType(i) == Cursor.FIELD_TYPE_FLOAT) { //Because cutting double
								val = "" + cursor.getDouble(i);
							} else {
								val = cursor.getString(i);
							}
						}
						xml+="	<"+cursor.getColumnName(i)+"><![CDATA["+val+"]]></"+cursor.getColumnName(i)+">\n";
					}

					String geom="";
					Cursor cursor2 = null;
					try {
						cursor2 = rdb.rawQuery("select lat,lon from frmlocust_locations where frmlocust_uid=? order by pos", new String[]{String.valueOf(uid)});
						if (cursor2.moveToFirst()) {
							String first = "[" + cursor2.getDouble(1) + "," + cursor2.getDouble(0) + "]";
							do {
								geom += "[" + cursor2.getDouble(1) + "," + cursor2.getDouble(0) + "],";
							} while (cursor2.moveToNext());
							geom += first;
							geom = "{\"type\":\"Polygon\",\"coordinates\":[[" + geom + "]]}";
						}
						xml += "	<geom><![CDATA[" + geom + "]]></geom>";
					}catch(Exception e){
						e.printStackTrace();
					}finally{
						if(cursor2!=null){ cursor2.close(); }
					}
					xml+="</metadata>";

					myThread.addRequest("sendFrmLocust","xml",MySynchronizationOld.URL+"/get/", xml, null,null,null);

				}while (cursor.moveToNext());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();
	}

	/**
	 * Отправить форму уничтожения саранчи из базы по идентификатору из базы
	 * @param uid
	 */
	public void sendFrmLocustDel(String uid)
	{
		if(uid==null || uid.equals("")) return;

		String xml="";
		DbOpenHelper dboh = new DbOpenHelper(_context);
		Cursor cursor = null;
		SQLiteDatabase rdb = null;
		try {
			rdb = dboh.getReadableDatabase();

			cursor = rdb.rawQuery("select * from frmlocustdel where uid=?", new String[] { String.valueOf(uid) });
			if(cursor.moveToFirst())
			{
				do{
					//Если задано имя файла то добавляем его в очередь на отправку на сервер
					String fname;
					fname=cursor.getString(cursor.getColumnIndex("image_name1"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic1","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);

					fname = cursor.getString(cursor.getColumnIndex("image_name2"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic2","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);

					fname = cursor.getString(cursor.getColumnIndex("image_name3"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic3","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);


					xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
					xml+="<metadata fn=\"5\">";
					for(int i=0;i<cursor.getColumnCount();i++)
					{
						String val="";
						if(!cursor.isNull(i)) {
							if (cursor.getType(i) == Cursor.FIELD_TYPE_FLOAT) { //Because cutting double
								val = "" + cursor.getDouble(i);
							} else {
								val = cursor.getString(i);
							}
						}
						xml+="	<"+cursor.getColumnName(i)+"><![CDATA["+val+"]]></"+cursor.getColumnName(i)+">\n";
					}
					String geom="";
					Cursor cursor2 = null;
					try {
						cursor2 = rdb.rawQuery("select lat,lon from frmlocustdel_locations where frmlocustdel_uid=? order by pos", new String[]{String.valueOf(uid)});
						if (cursor2.moveToFirst()) {
							String first = "[" + cursor2.getDouble(1) + "," + cursor2.getDouble(0) + "]";
							do {
								geom += "[" + cursor2.getDouble(1) + "," + cursor2.getDouble(0) + "],";
							} while (cursor2.moveToNext());
							geom += first;
							geom = "{\"type\":\"Polygon\",\"coordinates\":[[" + geom + "]]}";
						}
						xml += "	<geom><![CDATA[" + geom + "]]></geom>";
					}catch(Exception e){
						e.printStackTrace();
					}finally{
						if(cursor2!=null){ cursor2.close(); }
					}
					xml+="</metadata>";

					myThread.addRequest("sendFrmLocust","xml",MySynchronizationOld.URL+"/get/", xml, null,null,null);

					//Отправляю данные координат отдельно (без подтверждения доставки, потом нужно добавить поле send boolean и отправлять отдельно от frmlocustdel)
	/*				Cursor cursor3 = rdb.rawQuery("select uid,del,seq,frmlocustdel_uid,pos,lon,lat from frmlocustdel_locations where frmlocustdel_uid=? order by pos", new String[] { String.valueOf(uid) });
					ByteArrayOutputStream outStream = new ByteArrayOutputStream();
					TCTableTools2.getTCTableFromCursor("frmlocustdel_locations", 0, cursor3, outStream);
					myThread.addRequest(MySynchronizationOld.URL+"/asdc/tctable/", null, null, outStream.toByteArray());*/

					ByteArrayOutputStream outStream = new ByteArrayOutputStream();
					TCTable tbl = new TCTable("frmlocustdel_locations", 0);
					tbl.addField(new TCField("uid",TCField.BD_UTF8_1));
					tbl.addField(new TCField("del",TCField.BD_UINT1));
					tbl.addField(new TCField("seq",TCField.BD_UINT4));
					tbl.addField(new TCField("frmlocustdel_uid",TCField.BD_UTF8_1));
					tbl.addField(new TCField("pos",TCField.BD_UINT4));
					tbl.addField(new TCField("lon",TCField.BD_FLOAT8));
					tbl.addField(new TCField("lat",TCField.BD_FLOAT8));
					tbl.getHeader(outStream);
					//Переписываю значения из базы данных в outStream
					Cursor cursor3 = null;
					try {
						cursor3 = rdb.rawQuery("select uid,del,seq,frmlocustdel_uid,pos,lon,lat from frmlocustdel_locations where frmlocustdel_uid=? order by pos", new String[]{String.valueOf(uid)});
						if (cursor3.moveToFirst()) {
							do {
								tbl.fields.get(0).setValue(cursor3.getString(0));
								tbl.fields.get(1).setValue(cursor3.getString(1));
								tbl.fields.get(2).setValue(cursor3.getString(2));
								tbl.fields.get(3).setValue(cursor3.getString(3));
								tbl.fields.get(4).setValue(cursor3.getString(4));
								tbl.fields.get(5).setDoubleVal(cursor3.getDouble(5));
								tbl.fields.get(6).setDoubleVal(cursor3.getDouble(6));
								tbl.getCol(outStream);
							} while (cursor3.moveToNext());
						}
					}catch(Exception e){
						e.printStackTrace();
					}finally{
						cursor3.close();
					}
					//Отправляю пакет данных на сервер для вставки либо обновления
					myThread.addRequest(tbl.name,"",MySynchronizationOld.URL+"/asdc/tctable/", null,null, null, outStream.toByteArray());

				}while (cursor.moveToNext());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();
	}

	/**
	 * Отправить анкету для сохранения на сервер в виде JSON запроса
	 * @param uid Идентификатор записи
	 */
	public void sendFrmLocustHealth(String uid)
	{
		if(uid==null || uid.equals("")) return;

		JSONObject jsonObject = new JSONObject();

		DbOpenHelper dboh = new DbOpenHelper(_context);
		Cursor cursor = null;
		SQLiteDatabase rdb = null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select * from frmlocusthealth where uid=?", new String[] { String.valueOf(uid) });
			if(cursor.moveToFirst())
			{
				do{
					//Если задано имя файла то добавляем его в очередь на отправку на сервер
					String fname;
					fname=cursor.getString(cursor.getColumnIndex("image_name1"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic1","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);
					fname = cursor.getString(cursor.getColumnIndex("image_name2"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic2","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);
					fname = cursor.getString(cursor.getColumnIndex("image_name3"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic3","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);
					fname = cursor.getString(cursor.getColumnIndex("image_name4"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic4","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);
					fname = cursor.getString(cursor.getColumnIndex("image_name5"));
					if(fname!=null && !fname.equals(""))
						myThread.addRequest("pic5","xml",MySynchronizationOld.URL+"/get/?fn=6", null, null,Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Locust/" + fname,null);

					for(int i=0;i<cursor.getColumnCount();i++)
					{
						String columnName = cursor.getColumnName(i);
						String value=null;
						if(!cursor.isNull(i)) {
							if (cursor.getType(i) == Cursor.FIELD_TYPE_FLOAT) { //Because cutting double
								value = "" + cursor.getDouble(i);
							} else {
								value = cursor.getString(i);
							}
						}
						try {
							jsonObject.put(columnName, value);
						} catch (JSONException e) {
							throw new RuntimeException(e);
						}
					}
					myThread.addRequest("sendFrmLocustHealth","json",MySynchronizationOld.URL+"/asdc/frmlocusthealth/", null, jsonObject.toString(), null,null);

				}while (cursor.moveToNext());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();
	}

	//Для обновления справочников и загрузки старых анкет уничножения саранчи
	boolean makeRequest(String tableName,String days,String country_id)
	{
		String seq="";
		DbOpenHelper dboh = new DbOpenHelper(_context);
		SQLiteDatabase rdb = null;
		Cursor cursor = null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select max(seq) as seq from " + tableName + ";", null);
			if (cursor.moveToFirst()) {
				seq = cursor.getString(cursor.getColumnIndex("seq"));
			}
			if (seq == null) seq = "0";
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();
		if(days!=null && !days.isEmpty() && country_id!=null && !country_id.isEmpty()){
			return myThread.addRequest(tableName,"tbl",MySynchronizationOld.URL+"/get/?fn=1&r=0&n="+tableName+"&s=" + seq + "&l=1000&days="+days+"&country_id="+country_id+"&android_id="+android_id,"", null,null,null);
		}else{
			return myThread.addRequest(tableName,"tbl",MySynchronizationOld.URL+"/get/?fn=1&r=0&n="+tableName+"&s=" + seq + "&l=1000","", null,null,null);
		}
	}

	/**
	 * Синхронизовать данные с сервером (добавляет задания в поток)
	 * Если в задании синхронизации есть хоть 1 задание не должно синхронизироваться
	 * boolean bAll - Синхронизировать ли всё (задания и пользователи запрашиваются при запуске программы)
	 */
	public void Synch()
	{
		if(myThread.getCountTasks()!=0)
			return; //Не начинать новую синхронизацию текущая не закончилась (так мы защищаемся от повторной отправки)

		String xml="";

		android_id = Settings.Secure.getString(_context.getContentResolver(), Settings.Secure.ANDROID_ID);

		//Последовательно отправляю изменёные пользователям записи (send=0 и они заполнены)
		DbOpenHelper dboh = new DbOpenHelper(_context);
		SQLiteDatabase rdb = null;
		Cursor cursor = null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select uid from frmlocust where send=0 and filled=1 and device_id=?", new String[]{ android_id });
			if(cursor.moveToFirst())
			{
				do{
					sendFrmLocust(cursor.getString(cursor.getColumnIndex("uid")));
				}while (cursor.moveToNext());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();

		//Последовательно отправляю изменёные пользователям записи (send=0 и они заполнены)
		dboh = new DbOpenHelper(_context);
		rdb = null;
		cursor = null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select uid from frmlocustdel where send=0 and filled=1 and device_id=?", new String[]{ android_id });
			if(cursor.moveToFirst())
			{
				do{
					sendFrmLocustDel(cursor.getString(cursor.getColumnIndex("uid")));
				}while (cursor.moveToNext());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();

		//Последовательно отправляю изменёные пользователям записи (send=0 и они заполнены)
		dboh = new DbOpenHelper(_context);
		rdb = null;
		cursor =null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select uid from frmlocusthealth where send=0 and filled=1 and device_id=?", new String[]{ android_id });
			if(cursor.moveToFirst())
			{
				do{
					sendFrmLocustHealth(cursor.getString(0));
				}while (cursor.moveToNext());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();


		//Запрос в очередь на получение списка стран, направлений, итд.
		makeRequest("locuststypes",null,null);
		makeRequest("sprayers",null,null);
		makeRequest("sprayers_types",null,null);
		makeRequest("fledgling",null,null);
		makeRequest("list_density",null,null);
		makeRequest("list_phase",null,null);
		makeRequest("list_directions",null,null); //Стороны света (направления)
		makeRequest("list_damage",null,null); //Справочник степень повреждения растительного покрова
		makeRequest("list_mortality",null,null); //Справочник степень повреждения растительного покрова
		makeRequest("list_greenery",null,null);
		makeRequest("list_biotope",null,null);
		makeRequest("list_cover",null,null);
		makeRequest("list_age",null,null);
		makeRequest("list_actions",null,null);
		makeRequest("list_paintings",null,null);
		makeRequest("list_behaviors",null,null);
		makeRequest("list_breeding",null,null);
		makeRequest("list_capacities",null,null);
		makeRequest("list_markings",null,null);
		makeRequest("list_containers",null,null);
		makeRequest("list_containers_states",null,null);
		makeRequest("list_vegetation",null,null);
		makeRequest("list_formulation",null,null);
		makeRequest("list_height",null,null);
		makeRequest("list_enemies",null,null);
		makeRequest("list_purpose",null,null);
		makeRequest("list_impact",null,null);
		makeRequest("list_diluted",null,null);
		makeRequest("terminals",null,null);
		makeRequest("companies",null,null);
        makeRequest("countries",null,null); //Если есть хоть 1 запись то считается что справочники хоть 1 раз загрузились
		makeRequest("countriesregions",null,null);
		makeRequest("_languages",null,null);
		makeRequest("_translations",null,null);
		makeRequest("borns",null,null);  //Справочник отрождение "Начало", "Массовое".

		//Загружаю формы саранчовых обработок за последние X дней для страны Y
		dboh = new DbOpenHelper(_context);
		rdb = null;
		cursor = null;
		try {
			rdb = dboh.getReadableDatabase();
			cursor = rdb.rawQuery("select t.country_id from terminals t where t.del=0 and t.serial='"+ android_id +"';", null);
			if(cursor.moveToFirst())
			{
				String country_id = cursor.getString(0);
				makeRequest("frmlocustdel",String.valueOf(MySynchronizationOld.SyncDays),country_id);
				makeRequest("frmlocustdel_locations",String.valueOf(MySynchronizationOld.SyncDays),country_id);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(cursor!=null){ cursor.close(); }
			if(rdb!=null){ rdb.close(); }
		}
		dboh.close();
	}

	//Пришел ответ от HTTP сервера
	//Если резутьтат true то сохранено (данные корректны)
	//public boolean incomingData(int rid, byte[] data)

	/**
	 * Функция обрабатывает скаченные данные
	 * @param type Тип данных
	 * @param filePath файл с данными
	 * @return
	 */
	public boolean incomingData(String type, String filePath)
	{
		/*if (BuildConfig.DEBUG && ( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) )) {
			try {
				String log=Tools.getStringFromFile(filePath,1024);
				Log.e("CCALM", log);
			}catch(Exception ex)
			{}
		}*/

		Boolean result=true;
		if(filePath==null || filePath.equals("")) return false;
		File file=new File(filePath);
		if(!file.exists()) return false;
		FileInputStream is=null;
		try
		{
			is=new FileInputStream(file);

			DbOpenHelper dbOpenHelper = new DbOpenHelper(_context);

			if(type.equals("tbl"))
			{
				TCTable tbl=new TCTable("",0);
				if(tbl.OpenTableH(is))
				{
					if(tbl.name.equals("terminals"))
						Log.d("igor", "tbl.name = " + tbl.name);
					result = dbOpenHelper.updateTable(tbl);
				}
			}else if(type.equals("xml")) //Данные в виде XML файла
			{
				//Парсим файл
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				try {
					DocumentBuilder builder = factory.newDocumentBuilder();
					Document doc = null;
					try {
						doc = builder.parse(is);
					} catch (Exception e) {
						return false;
					}

					Element root = doc.getDocumentElement();

					String fn=root.getAttribute("fn");
					if (fn.equals("-1")) {
						String error= XMLTools.getCDATAValue(root);
						Log.e("CCALM", "Error = " + error);
						//MyAlert("ASDC: Error!",XMLTools.getCDATAValue(root));
					} else if (fn.equals("1")) //Пришли данные о пользователе устройства обновим либо добавим
					{
					} else if (fn.equals("2")) //Пришли данные заданий по сбору инфы о саранче
					{
					} else if (fn.equals("3")) //Пришли данные заданий по сбору инфы об уничтожении саранчи
					{
					} else if (fn.equals("4")) //Сохранили данные о саранче на сервере ставим признак отправленности
					{
						String uid = XMLTools.getCDATAValue(XMLTools.findFirstNode(root, "uid"));
						if (uid.isBlank() || uid == "null") uid = null;

						DbOpenHelper dboh = new DbOpenHelper(_context);
						SQLiteDatabase rdb = null;
						SQLiteDatabase wdb = null;
						Cursor cursor = null;
						try {
							rdb = dboh.getReadableDatabase();
							wdb = dboh.getWritableDatabase();

							ContentValues cv = new ContentValues();
							cv.put("send", 1); //Mark as sent
							//cv.put("changed", 0); //Отмечаем как не измененное

							wdb.beginTransaction(); //Вроде как защита от многопоточности (для сервиса)
							try {
								wdb.update("frmlocust", cv, "uid = ?", new String[]{String.valueOf(uid)});
								wdb.setTransactionSuccessful();
							}catch(Exception e){
								e.printStackTrace();
							} finally {
								wdb.endTransaction();
							}
							//Rename photo files to avoid sending them again.
							cursor = rdb.rawQuery("select image_name1, image_name2, image_name3 from frmlocust where uid=?;", new String[]{String.valueOf(uid)});
							if (cursor.moveToFirst()) {
								renameImage(cursor.getString(cursor.getColumnIndex("image_name1")));
								renameImage(cursor.getString(cursor.getColumnIndex("image_name2")));
								renameImage(cursor.getString(cursor.getColumnIndex("image_name3")));
							}
						}catch(Exception e){
							e.printStackTrace();
						}finally{
							if(cursor!=null){ cursor.close(); }
							if(rdb!=null){ rdb.close(); }
							if(wdb!=null){ wdb.close(); }
						}
						dboh.close();

					} else if (fn.equals("5")) //Сохранили данные о саранче на сервере ставим признак отправленности
					{
						String uid = XMLTools.getCDATAValue(XMLTools.findFirstNode(root, "uid"));
						if (uid.isBlank() || uid == "null") uid = null;

						DbOpenHelper dboh = new DbOpenHelper(_context);
						SQLiteDatabase rdb = null;
						SQLiteDatabase wdb = null;
						Cursor cursor = null;
						try {
							rdb = dboh.getReadableDatabase();
							wdb = dboh.getWritableDatabase();

							ContentValues cv = new ContentValues();
							cv.put("send", 1); //Mark as sent
							//cv.put("changed", 0); //Отмечаем как не измененное

							wdb.beginTransaction(); //Вроде как защита от многопоточности (для сервиса)
							try {
								wdb.update("frmlocustdel", cv, "uid = ?", new String[]{String.valueOf(uid)});
								wdb.setTransactionSuccessful();
							}catch(Exception e){
								e.printStackTrace();
							} finally {
								wdb.endTransaction();
							}

							//Rename photo files to avoid sending them again.
							cursor = rdb.rawQuery("select image_name1, image_name2, image_name3 from frmlocustdel where uid=?;", new String[]{String.valueOf(uid)});
							if (cursor.moveToFirst()) {
								renameImage(cursor.getString(cursor.getColumnIndex("image_name1")));
								renameImage(cursor.getString(cursor.getColumnIndex("image_name2")));
								renameImage(cursor.getString(cursor.getColumnIndex("image_name3")));
							}
						}catch(Exception e){
							e.printStackTrace();
						}finally{
							if(cursor!=null){ cursor.close(); }
							if(rdb!=null){ rdb.close(); }
							if(wdb!=null){ wdb.close(); }
						}

					} else if (fn.equals("6")) //Photo sent to server
					{
						Log.i("CCALM", "Photo sent to server!");
					}

				} catch (Exception e) {
					Log.e("CCALM", "Error", e);
				}
			}else if(type.equals("json"))
			{
				JSONObject jsonObject=null;
				String jsonString = Tools.readInputStream(is);
				if(jsonString!=null){
					try {
						jsonObject = new JSONObject(jsonString);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				if(jsonObject!=null){
					if(jsonObject.has("error_code"))
					{
						if(jsonObject.getInt("error_code")!=0)
						{
							Log.e("CCALM", "Error: "+jsonObject.getString("error_message"));
						}else{
							String fn=jsonObject.getString("fn");
							if(fn.equals("frmlocusthealth")){
								String uid = jsonObject.getString("uid");
								if (uid.isBlank() || uid == "null") uid = null;


								DbOpenHelper dboh = new DbOpenHelper(_context);
								SQLiteDatabase rdb = null;
								SQLiteDatabase wdb = null;
								Cursor cursor = null;
								try {
									rdb = dboh.getReadableDatabase();
									wdb = dboh.getWritableDatabase();

									ContentValues cv = new ContentValues();
									cv.put("send", 1); //Mark as sent
									//cv.put("changed", 0); //Отмечаем как не измененное

									wdb.beginTransaction(); //Вроде как защита от многопоточности (для сервиса)
									try {
										wdb.update("frmlocusthealth", cv, "uid = ?", new String[]{String.valueOf(uid)});
										wdb.setTransactionSuccessful();
									}catch(Exception e){
										e.printStackTrace();
									} finally {
										wdb.endTransaction();
									}

									//Rename photo files to avoid sending them again.
									cursor = rdb.rawQuery("select image_name1, image_name2, image_name3, image_name4, image_name5 from frmlocusthealth where uid=?;", new String[]{String.valueOf(uid)});
									if (cursor.moveToFirst()) {
										renameImage(cursor.getString(cursor.getColumnIndex("image_name1")));
										renameImage(cursor.getString(cursor.getColumnIndex("image_name2")));
										renameImage(cursor.getString(cursor.getColumnIndex("image_name3")));
										renameImage(cursor.getString(cursor.getColumnIndex("image_name4")));
										renameImage(cursor.getString(cursor.getColumnIndex("image_name5")));
									}
								}catch(Exception e){
									e.printStackTrace();
								}finally{
									if(cursor!=null){ cursor.close(); }
									if(rdb!=null){ rdb.close(); }
									if(wdb!=null){ wdb.close(); }
								}

							}
						}
					}
				}



				Log.e("CCALM", "Unknown JSON data type");
			}else{
				Log.e("CCALM", "Unknown data type");
			}



		} catch (Exception e) {
			result = false;
		}finally{
			if(is!=null) { try { is.close(); } catch (IOException e) { } }
			file.delete();
		}
		return result;
	}

}

/* Поток заданий на отправку данных на сервер */
class MyThread extends Thread
{
    class Tsk //Задание отправки данных
    {
		private static int mId=0; //Переменная для создания инкриментального идентификатора запроса

		int id = 0; //Инкриментальный идентификатор запроса

		String name = ""; //Название запроса для дебага
		String type = ""; //Тип ожидаемого результата, такие сейчас: "xml", "json", "tbl"

        String url = ""; //URL куда отправлять данные
        //String str = ""; //Отправляемая строка
		String xml = ""; //Отправляемая XML строка
		String json = ""; //Отправляемая JSON строка
        String file = ""; //Отправляемый файл
		byte[] data = null; //Отправляемые данные
        Boolean send = false; //Integer s = 0; // false - не отправлялось true - в процессе отправки (TODO поменять на int 0=не отправлялось, 1=в процессе отправки 2=отправленно, если ошибка то прибавляется 100 к статусу)

        int wait = 10; //Милисекунд ждать перед отправкой текущего задания
        int t=0; //Количество совершенных попыток отправки

		Tsk(){
			mId++;
			this.id=mId;
		}
    }

    private Semaphore mSemaphore = null; //Семафор для доступа к списку заданий
    private ArrayList<Tsk> mTList = new ArrayList<Tsk>(); //Защищёный список
    private MySynchronizationOld mListener = null; //Для отправки ответов в основной поток
    private String mAppPath = "";

    @SuppressLint("HandlerLeak")
    private final Handler myHandle = new Handler() //Для ловли сообщений из другого потока
    {
        @Override
        public void handleMessage(Message msg) //Слушатель ответа после отправки данных на сервер
        {
            String type = msg.getData().getString("type");
            boolean done = mListener.incomingData(type, msg.getData().getString("file")); //Слушатель должен вернуть true иниче запрос останется в очереди
			if(!done){
				Log.e("CCALM", "Failed to process data");
				//TODO вывести в лог приложения и наверно отправить накопившиеся на сайт
			}
        }
    };

    public MyThread(MySynchronizationOld listener, String appPath)
    {
        mListener = listener;
        mAppPath = appPath;
        assert(mListener != null);

        mSemaphore = new Semaphore(1);
    }

    // Добавление в задание на отправку до того как не получен ответ от предедущего запроса следующий не отсылается те. последовательно это делает (обработка результатов не в потоке загрузки а в основном потоке)
    //return id запроса
    public boolean addRequest(String name, String type,String url, String xml, String json, String file,byte[] data)
    {
		boolean result=false;
        try
        {
            mSemaphore.acquire();
            Tsk t = new Tsk();
			t.name = name;
			t.type = type; //waiting result data type
            t.url = url;
            t.xml = xml;
			t.json = json;
            t.file = file;
			t.data = data;
            t.send = false;
            mTList.add(t);

			result=true;
        } catch (InterruptedException ex)
        {
        } finally
        {	mSemaphore.release();
        }
        return result;
    }

    /**
     * Получить количество заданий ожидающих выполнение
     * @return
     */
    public int getCountTasks()
    {
        int result=0;
        try
        {
            mSemaphore.acquire();
            result = mTList.size();
        } catch (InterruptedException ex)
        {
        } finally
        {	mSemaphore.release();
        }
        return result;
    }

    @Override
    public void run()
    {
        Tsk tsk;
        while(true)
        {
            //Считываем первое задание из защищёного семафором списка
            tsk = null;
            try {
                mSemaphore.acquire();
                for(int i=0;i<mTList.size();i++)
                {
                    if(! mTList.get(i).send)
                    {	tsk = mTList.get(i);
                        break;
                    }
                }
				//Для дебага:
//				String names="";
//				int cnt1=0, cnt2=0;
//				for(int i=0;i<mTList.size();i++)
//				{
//					cnt1++;
//					if(! mTList.get(i).send)
//					{
//						names+=" "+mTList.get(i).name+" id="+String.valueOf(mTList.get(i).id);
//						cnt2++;
//					}else{
//						names+=" *"+mTList.get(i).name+" id="+String.valueOf(mTList.get(i).id);
//					}
//				}
//				Log.i("CCALM", "download task names = "+names+" cnt1 = "+String.valueOf(cnt1)+" cnt2 = "+String.valueOf(cnt2));

            } catch (InterruptedException ex) {
                // вот такое может произойти, если поток например прервут thread.interrupt()
            } finally {
                mSemaphore.release(); //Отдаем семафор
            }


            //Выполняем задание на отправку/приём данных
            if(tsk != null)
            {
				Log.i("CCALM", "download task = "+tsk.name + " time = " + tsk.t);
				if(tsk.name.equals("frmlocustdel")){
					Log.i("CCALM", "download task = "+tsk.name);
				}
                boolean bError=false;
                tsk.send = true; //Признак отправляемости запроса на сервер

                try {
                    sleep(tsk.wait); //Если в задании задано сколько подождать перед запуском
                } catch (InterruptedException ex) {
					Log.i("CCALM", "Sleep error",ex);
				}

                try
                {
					URL url = new URL(tsk.url);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setDoOutput(true);
					conn.setReadTimeout(60000); //60000 = 60 секунд
					conn.setConnectTimeout(15000);
					conn.setRequestMethod("POST");

					conn.setDoInput(true);
					conn.setDoOutput(true);

					if(tsk.file!=null) { //Отправляем файл на сервер
						File file = new File(tsk.file);
						if (file.exists()) {
							String boundary = UUID.randomUUID().toString();
							String crlf = "\r\n";
							conn.setRequestProperty("Connection", "Keep-Alive");
							conn.setRequestProperty("Cache-Control", "no-cache");
							conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
							//Так теперь сами данные обрамлённые границей
							DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
							dos.writeBytes("--" + boundary + crlf);
							dos.writeBytes("Content-Type: image/jpeg" + crlf);
							dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + tctable.Tools.afterLast(tsk.file, "/") + "\"" + crlf);
							dos.writeBytes(crlf);
							// Read file
							byte[] buffer = new byte[1024]; //The phone's resources are not unlimited, so we send a little at a time
							FileInputStream fileInputStream = new FileInputStream(file);
							int bytesRead = fileInputStream.read(buffer);
							try {
								while (bytesRead > 0) {
									try {
										dos.write(buffer, 0, bytesRead);
									} catch (OutOfMemoryError e) {
										//e.printStackTrace();
										Log.e("CCALM", "Error: ", e);
									}
									bytesRead = fileInputStream.read(buffer);
								}
							} catch (Exception e) {
								//e.printStackTrace();
								Log.e("CCALM", "Error: ", e);
							}
							fileInputStream.close();

							dos.writeBytes(crlf);
							dos.writeBytes("--" + boundary + "--" + crlf);
							dos.flush();
							dos.close();
						}
					}else if(tsk.data!=null) { //Отправляем двоичные данные на сервер
						String boundary = UUID.randomUUID().toString();
						String crlf = "\r\n";
						conn.setRequestProperty("Connection", "Keep-Alive");
						conn.setRequestProperty("Cache-Control", "no-cache");
						conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
						//Now we send the data itself, framed by a border.
						DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
						dos.writeBytes("--" + boundary + crlf);
						dos.writeBytes("Content-Type: application/octet-stream" + crlf);
						dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"bin_data.bin\"" + crlf);
						dos.writeBytes(crlf);
						dos.write(tsk.data, 0, tsk.data.length);
						dos.writeBytes(crlf);
						dos.writeBytes("--" + boundary + "--" + crlf);
						dos.flush();
						dos.close();
					}else if(tsk.xml!=null) {
						conn.setRequestProperty("Accept-Charset", "UTF-8");
						conn.setRequestProperty("Content-Type", "application/xml; charset=utf-8");
						conn.setRequestProperty("Accept", "application/xml");

						OutputStream os = conn.getOutputStream();
						BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
						writer.write(tsk.xml);
						writer.flush();
						writer.close();
						os.close();
					}else if(tsk.json!=null) {
						conn.setRequestProperty("Accept-Charset", "UTF-8");
						conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
						conn.setRequestProperty("Accept", "application/json");

						OutputStream os = conn.getOutputStream();
						BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
						writer.write(tsk.json);
						writer.flush();
						writer.close();
						os.close();
					}

					int responseCode=conn.getResponseCode();
					if (responseCode == HttpsURLConnection.HTTP_OK) {

						String filePath = mAppPath+"/"+"data_"+ String.valueOf(tsk.id)+".txt";

						//Так как файл может быть большим и он может не поместиться в памяти то сохраняем его на диск (допустим таблица с языками очень большая)
						try {
							BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
							BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(filePath)));
							int inByte;
							while ((inByte = bis.read()) != -1)
								bos.write(inByte);
							bis.close();
							bos.close();
						}catch(Exception e)
						{
							e.printStackTrace();
							Log.e("CCALM", "Error: ", e);
						}

						//Информирую слушателя о приёме данных
						Message msg = myHandle.obtainMessage();
						Bundle bundle = new Bundle();
						bundle.putString("file", filePath); //Путь к файлу
						bundle.putString("type", tsk.type); //Тип файла
						msg.setData(bundle);
						myHandle.sendMessage(msg);

					}else{
						Log.e("CCALM", "ERROR URL = "+tsk.url+" responseCode"+String.valueOf(responseCode));
					}
				} catch (Exception ex) {
					bError = true;
					Log.i("CCALM", "URL = "+tsk.url,ex);
				}

				//TODO при старте можно проверять совершен ли полный цикл загрузки без ошибок
				//Удаляю задание независемо как оно отработало (пусть на верхнем уровне думают пускать ли задание повторно)
				try
				{
					mSemaphore.acquire();
					for(int i=0; i<mTList.size();i++)
					{
						if(mTList.get(i).id==tsk.id)
						{
							mTList.remove(i);
							break;
						}
					}
				} catch (Exception e)
				{
					e.printStackTrace();
				} finally
				{	mSemaphore.release();
				}

            }

            try {
                sleep(100); //Задержка между каждым выполнением задания
            } catch (InterruptedException e) { }

        }
    }

}
