package com.jasamedika.medifirst2000.service.impl;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;

import org.hibernate.collection.internal.PersistentSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Service;

import com.jasamedika.medifirst2000.base.BaseModel;
import com.jasamedika.medifirst2000.base.BaseTransaction;
import com.jasamedika.medifirst2000.converter.PapAlergiConverter;
import com.jasamedika.medifirst2000.dao.GenericViewDao;
import com.jasamedika.medifirst2000.dao.PapAlergiDao;
import com.jasamedika.medifirst2000.dao.PasienDao;
import com.jasamedika.medifirst2000.dao.RegistrasiPelayananPasienDao;
import com.jasamedika.medifirst2000.dao.custom.GenericDaoCustom;
import com.jasamedika.medifirst2000.entities.PapKeluhanTambahan;
import com.jasamedika.medifirst2000.entities.GenericView;
import com.jasamedika.medifirst2000.entities.PapAlergi;
import com.jasamedika.medifirst2000.entities.Pasien;
import com.jasamedika.medifirst2000.entities.RegistrasiPelayananPasien;
import com.jasamedika.medifirst2000.exception.ServiceVOException;
import com.jasamedika.medifirst2000.service.GenericViewService;
import com.jasamedika.medifirst2000.service.PapAlergiService;
import com.jasamedika.medifirst2000.service.PasienService;
import com.jasamedika.medifirst2000.util.CommonUtil;
import com.jasamedika.medifirst2000.util.JsonUtil;
import com.jasamedika.medifirst2000.vo.PapKeluhanTambahanVO;
import com.jasamedika.medifirst2000.vo.PasienVO;
import com.jasamedika.medifirst2000.vo.PapAlergiVO;

/**
 * Implement class for PAPAlergiService
 * 
 * @author Askur
 */
@Service("GenericViewService")
public class PapGenericViewServiceImpl implements GenericViewService {
	@Autowired
	private GenericViewDao genericViewDao;
	@Autowired
	private GenericDaoCustom generic;

	@Override
	public List<GenericView> findGenericViewByPrevix(String namaPrevix) {
		List<GenericView> list = genericViewDao.findGenericViewByPrevix(namaPrevix);
		return list;
	}

	@Override
	public Object add(Object vo) throws JpaSystemException, ServiceVOException {
		return null;
	}

	@Override
	public Object update(Object vo) throws JpaSystemException, ServiceVOException {
		return null;
	}

	@Override
	public Boolean delete(Object key) throws JpaSystemException {
		return null;
	}

	@Override
	public Object findById(Object key) throws JpaSystemException {
		return null;
	}

	@Override
	public List findAll() throws JpaSystemException {
		return null;
	}

	@Override
	public Map findAllWithPageAndLimitAndSortByAndDirectionParameter(Integer page, Integer limit, String sort,
			String dir) {
		return null;
	}

	public List<Map<String, Object>> ToMaps(Object[] model) throws IllegalArgumentException, IllegalAccessException {

		List<Map<String, Object>> maps = new ArrayList<>();
		for (int i = 0; i < model.length; i++) {
			// for (Iterator iterator = model.iterator(); iterator.hasNext();) {
			BaseModel map = (BaseModel) model[i];
			Map<String, Object> convert = ToMap(map);
			maps.add(convert);
		}
		return maps;
	}

	public List<Map<String, Object>> ToMaps(List<Object> model)
			throws IllegalArgumentException, IllegalAccessException {

		List<Map<String, Object>> maps = new ArrayList<>();
		for (Iterator iterator = model.iterator(); iterator.hasNext();) {
			BaseModel map = (BaseModel) iterator.next();
			Map<String, Object> convert = (Map<String, Object>)JsonUtil.ToMapObject(map);
			maps.add(convert);
		}
		return maps;
	}

	public Map<String, Object> ToMap(BaseModel model) throws IllegalArgumentException, IllegalAccessException {
		Map<String, Object> maps = new HashMap<>();
		List<String> fieldsToInclude = new ArrayList<String>();
		for (Field field : model.GetFields(model.getClass())) {
			String str = field.getName();
			String name = field.getName();
			field.setAccessible(true);
			if (name.equals("serialVersionUID"))
				continue;
			Boolean valid = false;
			for (java.lang.annotation.Annotation annotation : field.getDeclaredAnnotations()) {
				if (annotation instanceof JoinColumn) {
					valid = true;
				} else if (annotation instanceof Column) {
					Column column = (Column) annotation;
					if (column.name().endsWith("Fk"))
						if (field.getName().endsWith("Id") == false)
							valid = true;
				} else if (annotation instanceof OneToMany) {

					valid = true;
				}

			}
			if (valid == false) {
				maps.put(field.getName(), field.get(model));
				System.out.println("maps >> " + field.getName());
			}

		}
		for (Field field : model.GetFields(model.getClass())) {
			String str = field.getName();
			String name = field.getName();
			field.setAccessible(true);
			if (name.equals("serialVersionUID"))
				continue;
			Boolean valid = false;
			for (java.lang.annotation.Annotation annotation : field.getDeclaredAnnotations()) {
				if (annotation instanceof JoinColumn) {
					valid = true;
				} else if (annotation instanceof Column) {
					Column column = (Column) annotation;
					if (column.name().endsWith("Fk"))
						if (field.getName().endsWith("Id") == false)
							valid = true;
				} else if (annotation instanceof OneToMany) {

					valid = true;
				}
				if (valid == true) {
					Object property = field.get(model);

					if (property == null)
						maps.put(str, null);
					else {
						if (property instanceof BaseModel) {
							Map<String, Object> mapItems = new HashMap<>();
							for (Field fieldItem : ((BaseModel) property).GetFields(property.getClass())) {
								String strItem = fieldItem.getName();
								String nameItem = fieldItem.getName();
								fieldItem.setAccessible(true);
								if (nameItem.equals("serialVersionUID"))
									continue;
								Boolean validItem = false;
								for (java.lang.annotation.Annotation annotationItem : fieldItem
										.getDeclaredAnnotations()) {
									if (annotationItem instanceof JoinColumn) {
										validItem = true;
									} else if (annotationItem instanceof Column) {
										Column columnItem = (Column) annotationItem;
										if (columnItem.name().endsWith("Fk"))
											if (fieldItem.getName().endsWith("Id") == false)
												validItem = true;
									} else if (annotationItem instanceof OneToMany) {

										validItem = true;
									}
								}
								if (validItem == false) {
									mapItems.put(fieldItem.getName(), fieldItem.get(property));
								}
							}
							System.out.println("maps >> " + str);
							maps.put(str, mapItems);
							for (Field fieldItem : ((BaseModel) property).GetFields(property.getClass())) {
								String strItem = fieldItem.getName();
								String nameItem = fieldItem.getName();
								fieldItem.setAccessible(true);
								if (nameItem.equals("serialVersionUID"))
									continue;
								Boolean validItem = false;
								for (java.lang.annotation.Annotation annotationItem : fieldItem
										.getDeclaredAnnotations()) {
									if (annotationItem instanceof JoinColumn) {
										validItem = true;
									} else if (annotationItem instanceof Column) {
										Column columnItem = (Column) annotationItem;
										if (columnItem.name().endsWith("Fk"))
											if (fieldItem.getName().endsWith("Id") == false)
												validItem = true;
									} else if (annotationItem instanceof OneToMany) {

										validItem = true;
									}
								}
								if (validItem == true) {
									Object propertyDetail = fieldItem.get(property);

									if (propertyDetail == null)
										mapItems.put(str, null);
									if (propertyDetail instanceof BaseModel) {
										Map<String, Object> mapItemsDetail = new HashMap<>();
										for (Field fieldItemDetail : ((BaseModel) propertyDetail)
												.GetFields(propertyDetail.getClass())) {
											String strItemDetail = fieldItemDetail.getName();
											String nameItemDetail = fieldItemDetail.getName();
											fieldItemDetail.setAccessible(true);
											if (nameItemDetail.equals("serialVersionUID"))
												continue;
											String validItemDetail = "0";
											for (java.lang.annotation.Annotation annotationItem : fieldItemDetail
													.getDeclaredAnnotations()) {
												if (annotationItem instanceof JoinColumn) {
													validItemDetail = "1";
												} else if (annotationItem instanceof Column) {
													Column columnItem = (Column) annotationItem;
													if (columnItem.name().endsWith("Fk"))
														{if (fieldItemDetail.getName().endsWith("Id") == false)
															validItemDetail = "1";
														}
													else
														validItemDetail = "2";
												} else if (annotationItem instanceof OneToMany) {

													validItemDetail = "1";
												} 
											}
											if (validItemDetail == "2") {
												System.out.println("mapItemsDetail >> " + fieldItemDetail.getName());
												mapItemsDetail.put(fieldItemDetail.getName(),
														fieldItemDetail.get(propertyDetail));
											}
										}
										System.out.println("mapItems >> " + fieldItem.getName());
										mapItems.put(fieldItem.getName(), mapItemsDetail);
									}
								}
							}

						} else if (property instanceof BaseTransaction) {
							Map<String, Object> mapItems = new HashMap<>();
							for (Field fieldItem : ((BaseTransaction) property).GetFields(property.getClass())) {
								String strItem = fieldItem.getName();
								String nameItem = fieldItem.getName();
								fieldItem.setAccessible(true);
								if (nameItem.equals("serialVersionUID"))
									continue;
								Boolean validItem = false;
								for (java.lang.annotation.Annotation annotationItem : fieldItem
										.getDeclaredAnnotations()) {
									if (annotationItem instanceof JoinColumn) {
										validItem = true;
									} else if (annotationItem instanceof Column) {
										Column columnItem = (Column) annotationItem;
										if (columnItem.name().endsWith("Fk"))
											if (fieldItem.getName().endsWith("Id") == false)
												validItem = true;
									} else if (annotationItem instanceof OneToMany) {

										validItem = true;
									}
								}
								if (validItem == false) {
									mapItems.put(fieldItem.getName(), fieldItem.get(property));
								}
							}
							maps.put(str, mapItems);
						} else if (property instanceof PersistentSet) {
							PersistentSet preseitent = (PersistentSet) property;

							maps.put(str, ToMaps(preseitent.toArray()));
						}
						System.out.println(property.getClass());

					}

				}
			}
		}
		return maps;
	}

	@Override
	public Map<String, Object> findMedicalRecordByNoCmAndTglInput(String previx, String noCm, Date tglInput) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(previx, ToMaps((List<Object>) generic.findMedicalRecordNoCmAndTglInput(previx, noCm, tglInput)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Map<String, Object> findByNoCmAndTglInput(String previx, String noCm, Date tglInput) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(previx, ToMaps((List<Object>) generic.findPapNoCmAndTglInput(previx, noCm, tglInput)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Map findByNoCmAnd(String previx, String noCm) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(previx, ToMaps((List<Object>) generic.findPapNoCm(previx, noCm)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Map findMedicalRecordByTglInput(String previx, Date from, Date until,String tgl) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(previx, ToMaps((List<Object>) generic.findMedicalRecordCustomTgl(previx, from, until,tgl)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Map findMedicalRecordByTglInput(String previx, Date from, Date until) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(previx, ToMaps((List<Object>) generic.findMedicalRecordTglInput(previx, from, until)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Autowired
	private PasienService pasienService;
	
	@Override
	public Map findMedicalRecordByNoRec(String i, String noRec) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(i, ToMaps((List<Object>) generic.findMedicalRecordNoRec(i,noRec)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Integer findByCountAntrian(String i, String noRec) {
				Integer map =0;

				try {
					map= generic.checkInputan(i,noRec);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				}
				return map;
	}

	@Override
	public Map<String, Object> findMedicalRecordByNoRecAndTglInput(String i, String noRec,Date tglInput) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(i, ToMaps((List<Object>) generic.findMedicalRecordNoRecAndTglInput(i,noRec,tglInput)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Map<String, Object> findMedicalRecordByNoRecAndTglInputPasien(String i, String noRec,Date tglInput) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(i, ToMaps((List<Object>) generic.findMedicalRecordNoRecAndTglInputPasien(i,noRec,tglInput)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}
	
	@Override
	public Map findMedicalRecordByNoRecAntrianPasienDiPeriksa(String i, String noRec) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(i, ToMaps((List<Object>) generic.findMedicalRecordNoRecAntrianPasienDiPeriksa(i,noRec)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}

	@Override
	public Map findMedicalRecordByNoRecPasienAntrianPasienDiPeriksa(String i, String noRec) {
		Map<String, Object> map = new HashMap<>();

		try {
			map.put(i, ToMaps((List<Object>) generic.findMedicalRecordPasienNoRecAntrianPasienDiPeriksa(i,noRec)));
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return map;
	}
}
