package UDP;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;public class Demo01_GUI extends JFrame {
	public static void main(String[] args) {
		gui1 = new Demo01_GUI();
		gui1.southPanel();
		gui1.centerPanel();
		gui1.init();
		gui1.event();
	}	private JPanel south;
	private JButton log;
	private JTextField tf; // 存ip
	private JButton send;
	private JButton clear;
	private JButton shake;
	private JPanel center;
	private TextArea viewText;
	private TextArea sendText;
	private DatagramSocket socket1;
	private DatagramSocket socket;
	private static Demo01_GUI gui1;
	private BufferedWriter bw;	public Demo01_GUI() {
		super("即时通讯");	}
	/**
	 * 初始化窗体JFrame
	 */
	public void init() {
		this.setSize(400, 600);// 设置窗体的大小
		Point point = new Point(800, 300);// 设置显示坐标
		this.setLocation(point);// 设置窗体的位置
		this.setVisible(true);// 显示出设置好的窗体
		try {
			bw = new BufferedWriter(new FileWriter("config.txt", true));// 初始化的时候就要创建出这个写入文件
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new Receive().start();// 启动接收消息线程	}
	/**
	 * 创建Frame窗体中南边的JPanel
	 */
	public void southPanel() {
		south = new JPanel();// 创建南边的JPanel
		tf = new JTextField(8);// 创建文本字段,存储IP地址
		tf.setText("127.0.0.1");// 给文本框设置默认的IP地址
		send = new JButton("发送");// 创建第一个发送按钮
		log = new JButton("记录");// 创建第一个记录按钮
		clear = new JButton("清除");// 创建第一个清屏按钮
		shake = new JButton("震动");// 创建第一个震动按钮
		// 先要把创建好的这些按钮和文本字段放到这个Panel里面
		south.add(tf);
		south.add(send);
		south.add(log);
		south.add(clear);
		south.add(shake);
		// 然后再把这个Panel添加到Frame框的南边(下边)
		this.add(south, BorderLayout.SOUTH);
	}	/**
	 * 创建Frame窗体中中间的JPanel
	 */
	public void centerPanel() {
		center = new JPanel(); // 创建中间的JPanel
		// 中间的panel需要两个Textarea
		viewText = new TextArea(); // 显示文本的区域
		sendText = new TextArea(4, 1); // 发送文本的区域
		center.setLayout(new BorderLayout());// 将JPanel设置为边界布局管理器
		// 设置完Panel为边界布局管理器之后,就可以吧viewText和sendText分别设置到中间和南边
		center.add(sendText, BorderLayout.SOUTH);// 将发送文本区域设置到南边
		center.add(viewText, BorderLayout.CENTER);// 将显示文本区域设置到中间
		viewText.setEditable(false);// 将显示文本区域设置为不可编辑
		viewText.setBackground(Color.WHITE);// 将显示文本区域背景颜色设置为白色
		viewText.setFont(new Font("xxx", Font.PLAIN, 15));// 设置输入字体大小
		sendText.setFont(new Font("xxx", Font.PLAIN, 15));// 设置显示区域字体大小
		this.add(center, BorderLayout.CENTER);// 然后再把这个JPanel添加到JFrame框的中间
	}	/**
	 * 设置关闭窗体按钮
	 */
	public void event() {
		// 这个是表示在窗口添加一个Windows事件消息,目的是我们关闭窗口的时候可以正常的退出
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				try {
					socket1.close();// 点击关闭窗体之前停止接收线程
					bw.close();// 关闭这个流
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				System.exit(0);
			}
		});
		send.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				try {
					send();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}		});
		log.addActionListener(new ActionListener() {			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				try {
					logFile();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}			/**
			 * 获取聊天记录
			 */
			private void logFile() throws IOException {
				// TODO Auto-generated method stub
				bw.flush();// 刷新缓冲区
				FileInputStream fis = new FileInputStream("config.txt");// 读取这个文件
				ByteArrayOutputStream baos = new ByteArrayOutputStream();// 在内存中创建缓冲区
				int len;
				byte[] arr = new byte[8192];
				while ((len = fis.read(arr)) != -1) {
					baos.write(arr, 0, len); // 将读取到的内容写入缓冲区
				}
				String str = baos.toString();// 将缓冲区中的内容转换成字符串
				viewText.setText(str);
				fis.close();
			}
		});
		/**
		 * 清屏功能
		 */
		clear.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				viewText.setText("");
			}
		});
		/**
		 * 触发屏幕震动功能
		 */
		shake.addActionListener(new ActionListener() {			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				try {
					send(new byte[] { -1 }, tf.getText());// 调用给指定ip发送消息这个方法
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});
		/**
		 * 监听点击键盘回车键发送消息
		 */
		sendText.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					try {
						send();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
		});	}
	/**
	 * 屏幕震动功能
	 */
	private void shake() {
		int x = this.getLocation().x;// 获取横坐标位置
		int y = this.getLocation().y;// 获取纵坐标位置
		for (int i = 0; i < 10; i++) { // 循环改变窗体的位置
			try {
				this.setLocation(x + 20, y + 20);
				Thread.sleep(20);
				this.setLocation(x + 20, y - 20);
				Thread.sleep(20);
				this.setLocation(x - 20, y + 20);
				Thread.sleep(20);
				this.setLocation(x - 20, y - 20);
				Thread.sleep(20);
				this.setLocation(x, y);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}	/**
	 * 接收和发送需要同时进行,所以定义成多线程的
	 * 
	 * @author lenovo 接收消息
	 */
	private class Receive extends Thread {		public void run() {
			try {
				socket1 = new DatagramSocket(9996);
				DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
				while (true) {
					socket1.receive(packet);// 接收信息
					byte[] arr = packet.getData(); // 获取字节数据
					int len = packet.getLength();// 获取有效的字节数据
					if (arr[0] == -1 && len == 1) {// 如果发过来的数组第一个存储的值是-1,并且数组长度是1
						shake();
						continue;
					}
					String message = new String(arr, 0, len);// 将接收到的有效字节转换成字符串
					String time = getCurrentTime();// 获取当前时间
					String ip = packet.getAddress().getHostAddress();// 获取ip地址
					String str = time + " " + ip + "对我说:\r\n\r\n" + message + "\r\n\r\n";
					bw.write(str);// 将接收的消息写入数据库
					viewText.append(str);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}	/**
	 * 给指定ip发送消息
	 * 
	 * @param arr
	 * @param ip
	 * @throws IOException
	 */
	private void send(byte[] arr, String ip) throws IOException {
		DatagramPacket packet = new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 9996);
		socket.send(packet);// 发送数据
	}	/**
	 * 发送消息
	 * 
	 * @throws IOException
	 */
	private void send() throws IOException {
		// TODO Auto-generated method stub
		String message = sendText.getText(); // 获取发送区域的内容
		String ip = tf.getText(); // 获取ip地址
		ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
		socket = new DatagramSocket();
		send(message.getBytes(), ip);// 调用send方法给指定ip发送消息
		String time = getCurrentTime(); // 拿到当前时间
		String str = time + "我对:" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "说 \r\n\r\n" + message + "\r\n\r\n"; // alt+shift+L 抽取局部变量
		viewText.append(str); // 将发送的信息添加到显示区域中
		bw.write(str); // 将发送的消息写入数据库中
		sendText.setText("");// 清空发送区域	}
	/**
	 * 获取到当前系统时间
	 * 
	 * @return
	 */
	private String getCurrentTime() {
		Date date = new Date(); // 创建当前日期对象
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");// 格式化
		return sdf.format(date); // 返回格式化后的时间
	}}