//==============================================================
//  版权所有：深圳杰文科技
//  文件名：BarcodeGenerator.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections.Generic;
using System.Threading;

namespace Infrastructure.Utilities
{
	public static class BarcodeGenerator
	{
		#region - EAN8 -

		//EAN8只有前面7位可用，最后一位是校验码，是根据前面7位数字计算出来的。
		public static string GenerateEAN8(string prefix)
		{
			string barcode = prefix;

			Thread.Sleep(20); //如果两次调用的时间太短，会导致生成的条码重复。
			Random rnd = new Random();

			int n = 0;
			int count = 8 - prefix.Length;
			for (int i = 1; i < count; i++) //生成7位随机码。
			{
				n = rnd.Next(10); //范围为0..9。
				if (i == 1 && n == 0)
				{
					//EAN-13与UPA-A码兼容，会导致扫描枪以为第一位数字为0的EAN-13码是UPA-A码。因此强制改为非0。
					n = (int)DateTime.Today.DayOfWeek + 3; //取星期会导致9数偏少，所以加3，加大9数的出现机会。
				}
				barcode = barcode + n.ToString();
			}

			barcode = barcode + CreateChecksumForEAN8(barcode);
			return barcode;
		}

		private static string CreateChecksumForEAN8(string EAN)
		{
			/*
			EAN8 检查和的计算方法：
			定义最右边的位为奇数位，前一位为偶数位，依次往左类推：
			数据： 0 9 2 3 4 5 7
			位置： O E O E O E O
			奇数位和： 0 + 2 + 4 + 7 = 13, 13 * 3 = 39
			偶数位和： 9 + 3 + 5 = 17
			奇偶位和： 17 + 39 = 56
			检查和：60 - 56 = 4 （ 60 是 56 向上取整到 10 的倍数 ）
			 */

			int count1 = 0; //奇数和。
			int count2 = 0; //偶数和。

			for (int i = 1; i < 8; i++)
			{
				string s = EAN.Substring(i - 1, 1);
				int n = int.Parse(s);

				if (i % 2 == 0) //如果是偶数位，
				{
					count2 += n;
				}
				else //否则是奇数位。
				{
					count1 += n;
				}
			}

			count1 = count1 * 3;

			int sum = count1 + count2;
			int checksum = ((int)(sum / 10)) * 10 + 10;

			checksum = checksum - sum;
			if (checksum == 10)
			{
				checksum = 0;
			}

			return checksum.ToString();
		}

		#endregion

		#region - EAN13 -

		//生成EAN-13条码。
		public static string GenerateEAN13(string prefix)
		{
			string barcode = prefix; //条码前缀。

			Thread.Sleep(20);
			Random rnd = new Random();

			int n = 0;
			int count = 13 - prefix.Length;
			for (int i = 1; i < count; i++) //生成N位随机码。
			{
				n = rnd.Next(10); //范围为0..9。
				if (i == 1 && n == 0)
				{
					//EAN-13与UPA-A码兼容，会导致扫描枪以为第一位数字为0的EAN-13码是UPA-A码。因此强制改为非0。
					n = (int)DateTime.Today.DayOfWeek + 3; //取星期会导致9数偏少，所以加3，加大9数的出现机会。
				}
				barcode = barcode + n.ToString();
			}

			barcode = barcode + CreateChecksumForEAN13(barcode);
			return barcode;
		}

		private static string CreateChecksumForEAN13(string EAN)
		{
			int csumTotal = 0;

			for (int charPos = EAN.Length - 1; charPos >= 0; charPos--)
			{
				if (charPos % 2 == 0)
					csumTotal = csumTotal + int.Parse(EAN.Substring(charPos, 1));
				else
					csumTotal = csumTotal + (3 * int.Parse(EAN.Substring(charPos, 1)));
			}

			int remainder = 10 - (csumTotal % 10);
			remainder = remainder % 10;
			return remainder.ToString();
		}

		#endregion

		static void Test()
		{
			for (int i = 0; i < 100; i++)
			{
				string barcode = GenerateEAN8("");
				Console.WriteLine(barcode);
			}
		}

	}

}