import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import org.junit.Test;
import org.junit.Assert;
import org.junit.Ignore;

import org.apache.commons.lang3.builder.ToStringBuilder;

import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Date;
import java.util.Properties;
import java.io.InputStream;
import java.io.IOException;

public class DAOEx02
{
	private static final Logger LOGGER = LogManager.getLogger(DAOEx02.class);
    Scanner sc = new Scanner(System.in);
	@Test
    @Ignore
	public void testLogin()
	{
		LOGGER.info("---- 欢迎光临宠物乐园 ----");
        LOGGER.info("请输入登录名:");
        String username = sc.next();
        LOGGER.info("请输入密码:");
        String password = sc.next();
        Master master = new Master(username, password);
		
		MasterDao masterdao = new MasterDaoImpl();

		MasterServiceImpl msi = new MasterServiceImpl(masterdao);

        msi.login(master);

		// Assert.assertEquals(true, msi.login(master));
	}

    @Test
    public void testAdoptPet()
    {
        MasterService masterService = new MasterServiceImpl();
        Assert.assertEquals(true, masterService.adoptPet());
    }
	
}

class Master
{
	private int id;
	private String username;
	private String password;

	public Master()
	{

	}

	public Master(String username, String password)
	{
		this.username = username;
		this.password = password;
	}

	public String getUsername()
	{
		return this.username;
	}

	public String getPassword()
	{
		return this.password;
	}
}

// 提供数据库连接服务
class DBHelper
{
    private static final Logger LOGGER = LogManager.getLogger(DBHelper.class);

    // 单例模式 在整个应用中有且仅有一个实例
    // 饿汉式单例
    private static final DBHelper INSTANCE = new DBHelper();

    // 构造函数私有化
    private DBHelper(){}

    // 提供一个获取实例的方法
    public static DBHelper getInstance()
    {
        return INSTANCE;
    }

    public Connection getConnection()
    {
        String url = null;
        String username = null;
        String password = null;

        InputStream in = null;
        
        try
        {

            // 将当前路径下config文件夹下的db.properties文件读取到流中
            in = DBHelper.class.getResourceAsStream("/config/db.properties");

            // 创建一个Properties对象,它继承HashTable
            Properties props = new Properties();

            // Properties加载流
            props.load(in);

            url = props.getProperty("url");
            username = props.getProperty("username");
            password = props.getProperty("password");


        }
        catch(IOException e)
        {
            LOGGER.warn("未找到config/db.properties文件");
            return null;
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch(IOException e)
                {
                    LOGGER.catching(e);
                }
            }
        }

        Connection conn = null;
        try
        {

            // NO.1 反射 加载Oracle的JDBC驱动
            Class.forName("oracle.jdbc.driver.OracleDriver");

            
            // NO.2 获取连接
            conn = DriverManager.getConnection(url, username, password);
           
        }
        catch(ClassNotFoundException e)
        {
            LOGGER.warn("未找到驱动类");
            LOGGER.catching(e);
        }
        catch(SQLException e)
        {
            LOGGER.catching(e);
        }

        return conn;
    }

    public static void closeConnection(Connection conn)
    {
        if (conn != null)
        {
            try
            {
                conn.close();
               
            }
            catch(SQLException e)
            {
                LOGGER.catching(e);
            }
        }
    }

    public static void closeStatement(PreparedStatement stat)
    {
        if (stat != null)
        {
            try
            {
                stat.close();
               
            }
            catch(SQLException e)
            {
                LOGGER.catching(e);
            }
        }
    }

    public static void closeResultSet(ResultSet rs)
    {
        if (rs != null)
        {
            try
            {
                rs.close();
                
            }
            catch(SQLException e)
            {
                LOGGER.catching(e);
            }
        }
    }

}

// SERVICE
interface MasterService
{
	boolean login(Master master);
    boolean adoptPet();
}

class MasterServiceImpl implements MasterService
{
	private static final Logger LOGGER = LogManager.getLogger(MasterServiceImpl.class);
    Scanner sc = new Scanner(System.in);
    private MasterDao masterdao;

	public MasterServiceImpl()
	{

	}

	public MasterServiceImpl(MasterDao masterdao)
	{
		this.masterdao = masterdao;
	}

	public boolean login(Master master)
	{
		
		MasterDaoImpl mdi = new MasterDaoImpl();
		int result = mdi.findMaster(master);

		if(result == 1)
		{
			LOGGER.info("登陆成功!");
            return true;
		}

		else
		{
			LOGGER.info("用户名或密码错误!");
            return false;
		}
	}

    public boolean adoptPet()
    {
        LOGGER.info("----欢迎光临宠物乐园----");
        LOGGER.info("请输入登陆名:");
        String username = sc.next();
        LOGGER.info("请输入密码:");
        String password = sc.next();
        Master master = new Master(username, password);
        if (!login(master)) 
        {
            return false;
        }

        LOGGER.info("请选择宠物类型:");
        PetTypeDao petTypeDao = new PetTypeDaoImpl();
        List<String> petTypes = petTypeDao.findAllPetType();

        StringBuffer sb = new StringBuffer();
        for (String element: petTypes) 
        {
            sb.append(element).append(" | ");
        }

        LOGGER.info(sb);

        String select = sc.next();
        int petTypeId = petTypeDao.findPetTypeId(select);
        if (petTypeId == 0) 
        {
            LOGGER.info("宠物类型输入有误,领养失败!");
            return false;
        }

        LOGGER.info("您选择的宠物类型编号是{}", petTypeId);
        LOGGER.info("请输入宠物昵称:");
        String name = sc.next();
        Pet pet = new Pet(1, username, name, new PetType(petTypeId, select), 60, 0, new Date(System.currentTimeMillis()), "良好");
        PetDao petDao = new PetDaoImpl();
        if (petDao.save(pet) == 1) 
        {
            petDao.closeConnection();
            return true;
        }
        petDao.closeConnection();
        return false;
    }
}

// DAO
interface MasterDao
{
	int findMaster(Master master);
}

class MasterDaoImpl implements MasterDao
{
	private static final Logger LOGGER = LogManager.getLogger(MasterDaoImpl.class);
	Connection conn = null;
	PreparedStatement stat = null;
	ResultSet rs = null;
	DBHelper dbHelper = null;
	int result = 0;

	public int findMaster(Master master)
	{
		
		try
		{
			dbHelper = DBHelper.getInstance();
       		conn = dbHelper.getConnection();

        	Assert.assertNotNull(conn);

			String sql = "SELECT COUNT(*) FROM tbl_master WHERE username = ? AND password = ?";

			stat = conn.prepareStatement(sql);
			stat.setString(1, master.getUsername());
			stat.setString(2, master.getPassword());

			rs = stat.executeQuery();

			if(rs.next())
			{
				result = rs.getInt("COUNT(*)");
			}	
				
		}

		catch(SQLException e)
		{
			LOGGER.catching(e);
		}

		finally
		{
			DBHelper.closeResultSet(rs);
			DBHelper.closeStatement(stat);
		}
		return result;			
	}
}

interface PetDao
{
    int save(Pet pet);
    int delete(Pet pet);
    int update(Pet pet);
    void closeConnection();
}

class PetDaoImpl implements PetDao
{
    private static final Logger LOGGER = LogManager.getLogger(PetDaoImpl.class);

    private Connection conn = DBHelper.getInstance().getConnection();

    @Override
    public int save(Pet pet)
    {
        PreparedStatement psmt = null;
        int result = 0;

        try
        {
            String sql = "INSERT INTO pet VALUES(?, ?, ?, ?, ?, ?, ?, ?)";
            psmt = conn.prepareStatement(sql);
            psmt.setInt(1, pet.getId());
            psmt.setString(2, pet.getMasterId());
            psmt.setString(3, pet.getName());
            psmt.setInt(4, pet.getPetType().getId());
            psmt.setInt(5, pet.getHealth());
            psmt.setInt(6, pet.getLove());
            psmt.setDate(7, pet.getAdoptTime());
            psmt.setString(8, pet.getStatus());

            result = psmt.executeUpdate();

        }
        catch(SQLException e)
        {
            LOGGER.catching(e);
        }
        finally
        {
            DBHelper.closeStatement(psmt);
        }

        return result;
    }

    @Override
    public int delete(Pet pet)
    {
        PreparedStatement psmt = null;
        int result = 0;

        try
        {
            String sql = "DELETE FROM tbl_pet WHERE id = ?";
            psmt = conn.prepareStatement(sql);
            psmt.setInt(1, pet.getId());

            result = psmt.executeUpdate();

        }
        catch(SQLException e)
        {
            LOGGER.catching(e);
        }
        finally
        {
            DBHelper.closeStatement(psmt);
        }

        return result;
    }

    @Override
    public int update(Pet pet)
    {
        PreparedStatement psmt = null;
        int result = 0;

        try
        {
            String sql = "UPDATE pet SET master_username = ?, name = ?, type_id = ?, health = ?, love = ?, adopt_time = ?, status = ? WHERE id = ?";
            psmt = conn.prepareStatement(sql);
            psmt.setString(1, pet.getMasterId());
            psmt.setString(2, pet.getName());
            psmt.setInt(3, pet.getPetType().getId());
            psmt.setInt(4, pet.getHealth());
            psmt.setInt(5, pet.getLove());
            psmt.setDate(6, pet.getAdoptTime());
            psmt.setString(7, pet.getStatus());
            psmt.setInt(8, pet.getId());

            result = psmt.executeUpdate();
        }
        catch(SQLException e)
        {
            LOGGER.catching(e);
        }
        finally
        {
            DBHelper.closeStatement(psmt);
        }

        return result;
    }

    @Override
    public void closeConnection()
    {
        DBHelper.closeConnection(conn);
    }
}

interface PetTypeDao
{
    List<String> findAllPetType();
    int findPetTypeId(String name);
}

class PetTypeDaoImpl implements PetTypeDao
{
    private static final Logger LOGGER = LogManager.getLogger(PetTypeDaoImpl.class);

    @Override 
    public List<String> findAllPetType()
    {
        DBHelper dbHelper = DBHelper.getInstance();
        Connection conn = dbHelper.getConnection();
        PreparedStatement psmt = null;
        ResultSet rs = null;
        List<String> list = new ArrayList<>();

        try
        {
            String sql = "SELECT name FROM pet_type";
            psmt = conn.prepareStatement(sql);

            rs = psmt.executeQuery();

            while (rs.next()) 
            {
                list.add(rs.getString(1));
            }

        }
        catch(SQLException e)
        {
            LOGGER.catching(e);
        }
        finally
        {
            DBHelper.closeResultSet(rs);
            DBHelper.closeStatement(psmt);
            DBHelper.closeConnection(conn);
        }
        

        return list;
    }

    @Override
    public int findPetTypeId(String name)
    {

        DBHelper dbHelper = DBHelper.getInstance();
        Connection conn = dbHelper.getConnection();
        PreparedStatement psmt = null;
        ResultSet rs = null;
        int result = 0;

        try
        {
            String sql = "SELECT id FROM pet_type WHERE name = ?";
            psmt = conn.prepareStatement(sql);
            psmt.setString(1, name);
            rs = psmt.executeQuery();

            if (rs.next()) 
            {
                result = rs.getInt(1);
            }

        }
        catch(SQLException e)
        {
            LOGGER.catching(e);
        }
        finally
        {
            DBHelper.closeResultSet(rs);
            DBHelper.closeStatement(psmt);
            DBHelper.closeConnection(conn);
        }
        

        return result;
    }
}

class PetType
{
    private int id;
    private String name;

    public PetType()
    {

    }

    public PetType(int id, String name)
    {
        this.id = id;
        this.name = name;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public int getId()
    {
        return this.id;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return this.name;
    }

    @Override
    public String toString()
    {
        return ToStringBuilder.reflectionToString(this);
    }
}

class Pet
{
    private int id;
    private String masterId;
    private String name;
    private PetType petType;
    private int health;
    private int love;
    private Date adoptTime;
    private String status;

    public Pet()
    {

    }

    public Pet(int id, String masterId, String name, PetType petType, int health, int love, Date adoptTime, String status)
    {
        this.id = id;
        this.masterId = masterId;
        this.name = name;
        this.petType = petType;
        this.health = health;
        this.love = love;
        this.adoptTime = adoptTime;
        this.status = status;
    }

    public int getId()
    {
        return this.id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getMasterId()
    {
        return this.masterId;
    }

    public void setMasterId(String masterId)
    {
        this.masterId = masterId;
    }

    public String getName()
    {
        return this.name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public PetType getPetType()
    {
        return this.petType;
    }

    public void setTypeId(PetType petType)
    {
        this.petType = petType;
    }

    public int getHealth()
    {
        return this.health;
    }

    public void setHealth(int health)
    {
        this.health = health;
    }

    public int getLove()
    {
        return this.love;
    }

    public void setLove(int love)
    {
        this.love = love;
    }

    public Date getAdoptTime()
    {
        return this.adoptTime;
    }

    public void setAdoptTime(Date adoptTime)
    {
        this.adoptTime = adoptTime;
    }

    public String getStatus()
    {
        return this.status;
    }

    public void setStatus(String status)
    {
        this.status = status;
    }
}