package com.nsgk.ruralWeb.location;

import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.location.CoordinateConverter;
import com.amap.api.location.DPoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

// 主线程调用, 无线程安全
public class NSRealtimeLocation implements LocationListener
{
    // 定位提供器
    public static final int FLAG_PROVIDER_NETWORK    = 1; // 网络定位
    public static final int FLAG_PROVIDER_GPS = 1 << 1; // GPS定位

    // 定位提供器优先级
    public static final int FLAG_PRIORITY_NETWORK = 1 << 2; // 网络定位优先
    public static final int FLAG_PRIORITY_GPS = 1 << 3; // GPS定位优先

    // 线程
    public static final int FLAG_BUILTIN_THREAD = 1 << 4; // 使用内建线程
    public static final int FLAG_CUSTOM_THREAD  = 1 << 5; // 使用外部线程
    public static final int FLAG_MAIN_THREAD    = 1 << 6; // 使用主线程

    public static final int DEFAULT_FLAG = FLAG_PROVIDER_NETWORK | FLAG_PROVIDER_GPS | FLAG_PRIORITY_NETWORK;


    public static final int OPTION_MIN_TIME     = 1; // 最小定位间隔(毫秒) 默认60000
    public static final int OPTION_MIN_DISTANCE = 2; // 最小定位距离变化(米) 默认10

    private static final int DEFAULT_MIN_TIME = 1000;
    private static final int DEFAULT_MIN_DISTANCE = 1;

    private static final String ID_TAG = NSRealtimeLocation.class.getName();

    private final Object m_lock = new Object();

    private LocationManager m_locationManager;
    private final  Context         m_context;
    private       int                      m_flag            = DEFAULT_FLAG;
    private NSLocationInfo m_lastLocation = null;
    private HandlerThread  m_thread       = null;
    private       Looper                   m_customLooper    = null;
    private       AtomicInteger            m_readOnce        = new AtomicInteger(-1);
    private       Map<Integer, Object>     m_options         = new HashMap<>();
    private String m_provider = null;
    private Looper m_looper = null;

    public NSRealtimeLocation(Context context)
    {
        m_context = context;
    }

    public boolean Init(int flag)
    {
        if(IsInitialized())
        {
            Log.e(ID_TAG, "定位已初始化");
            return true;
        }

        if(!HasFlag(FLAG_PROVIDER_NETWORK | FLAG_PROVIDER_GPS))
        {
            Log.e(ID_TAG, "请设置定位提供器");
            return false;
        }

        try
        {
            m_readOnce.set(-1);
            m_flag = flag < 0 ? DEFAULT_FLAG : flag;

            m_locationManager = (LocationManager) m_context.getSystemService(Context.LOCATION_SERVICE);

            //初始化定位
            if(HasFlag(FLAG_BUILTIN_THREAD))
            {
                m_thread = new HandlerThread("系统实时内建定位");
                m_thread.start();
                m_looper = m_thread.getLooper();
                Log.d(ID_TAG, "定位使用内建线程: " + m_thread.getId());
            }
            else if(HasFlag(FLAG_CUSTOM_THREAD))
            {
                if(null == m_customLooper)
                {
                    throw new RuntimeException("请先传入线程Looper");
                }
                m_looper = m_customLooper;
                Log.d(ID_TAG, "定位使用用户指定线程: " + m_customLooper.getThread().getId());
            }
            else if(HasFlag(FLAG_MAIN_THREAD))
            {
                Looper mainLooper = Looper.getMainLooper();
                m_looper = mainLooper;
                Log.d(ID_TAG, "定位使用主线程: " + mainLooper.getThread().getId());
            }
            else
            {
                m_looper = Looper.myLooper();
                Log.d(ID_TAG, "定位使用当前线程: " + Thread.currentThread().getId());
            }

            Log.i(ID_TAG, "定位初始化完成");
            return true;
        }
        catch(Exception e)
        {
            e.printStackTrace();
            m_locationManager = null;
            return false;
        }
    }

    public void SetThread(Looper looper)
    {
        CheckInitialization(false);
        m_customLooper = looper;
    }

    public void SetThread(HandlerThread thread)
    {
        CheckInitialization(false);
        m_customLooper = thread.getLooper();
    }

    public boolean IsRunning()
    {
        return IsInitialized() && null != m_provider;
    }

    public void Start()
    {
        Run(-1);
    }

    public void Stop()
    {
        CheckInitialization(true);

        m_locationManager.removeUpdates(this);
        m_provider = null;

        Log.i(ID_TAG, "定位停止");
    }

    public void Shutdown()
    {
        if(!IsInitialized())
        {
            Log.e(ID_TAG, "请先初始化");
            return;
        }

        Stop();

        m_locationManager = null;
        if(null != m_thread)
        {
            m_thread.quit();
            m_thread = null;
            Log.d(ID_TAG, "内建线程结束");
        }

        Log.i(ID_TAG, "定位销毁");
    }

    public boolean IsInitialized()
    {
        return null != m_locationManager;
    }

    private void CheckInitialization(boolean inited)
    {
        if(IsInitialized() != inited)
        {
            String msg = inited ? "定位未初始化" : "定位已初始化";
            Log.e(ID_TAG, msg);
            throw new RuntimeException(msg);
        }
    }

    private boolean HasFlag(int f)
    {
        return (m_flag & f) != 0;
    }

    public void SetOption(int type, Object value)
    {
        //CheckInitialization(false);
        m_options.put(type, value);
    }

    @SuppressLint("unchecked")
    private <T> T GetOption(int type, T def)
    {
        Object o = m_options.get(type);
        if(null == o)
            return def;
        return (T) o;
    }

    private void InitOptions()
    {
        List<String> providers = new ArrayList<>();
        m_provider = null;
        if(HasFlag(FLAG_PROVIDER_NETWORK))
        {
            if(m_locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
                providers.add(LocationManager.NETWORK_PROVIDER);
            else
                Log.w(ID_TAG, "网络定位提供器未启用");
        }
        if(HasFlag(FLAG_PROVIDER_GPS))
        {
            if(m_locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
                providers.add(LocationManager.GPS_PROVIDER);
            else
                Log.w(ID_TAG, "GPS定位提供器未启用");
        }
        if(providers.isEmpty())
            throw new RuntimeException("无定位提供器");

        if(HasFlag(FLAG_PRIORITY_NETWORK))
        {
            if(providers.contains(LocationManager.NETWORK_PROVIDER))
                m_provider = LocationManager.NETWORK_PROVIDER;
            else
                m_provider = LocationManager.GPS_PROVIDER;
        }
        else if(HasFlag(FLAG_PRIORITY_GPS))
        {
             if(providers.contains(LocationManager.GPS_PROVIDER))
                 m_provider = LocationManager.GPS_PROVIDER;
             else
                 m_provider = LocationManager.NETWORK_PROVIDER;
        }
/*        else
        {
            if(providers.contains(LocationManager.NETWORK_PROVIDER))
                m_provider = LocationManager.NETWORK_PROVIDER;
            else
                m_provider = LocationManager.GPS_PROVIDER;
        }*/

        if(null == m_provider)
            throw new RuntimeException("未确定定位提供器");

        Log.i(ID_TAG, "使用定位器: " + m_provider);
    }

    @SuppressLint("MissingPermission")
    private void Run(int num)
    {
        CheckInitialization(true);

        Stop();

        m_readOnce.set(num);

        InitOptions();

        int minTime = GetOption(OPTION_MIN_TIME, DEFAULT_MIN_TIME);
        int minDistance = GetOption(OPTION_MIN_DISTANCE, DEFAULT_MIN_DISTANCE);
        m_locationManager.requestLocationUpdates(m_provider, minTime, minDistance, this, m_looper);

        Location lastKnownLocation = m_locationManager.getLastKnownLocation(m_provider);
        SetLastLocation(lastKnownLocation);

        Log.i(ID_TAG, "定位开始");
    }

    private void SetLastLocation(Location location)
    {
        if(null != location)
        {
            m_lastLocation = new NSLocationInfo(location.getProvider(), location.getLongitude(), location.getLatitude());
        }
        else
        {
            m_lastLocation = null;
        }
    }

    /**
     * 同步调用, 会锁住线程
     */
    public NSLocationInfo Read(int count)
    {
        CheckInitialization(true);
/*        if(IsRunning())
        {
            throw new RuntimeException("请先停止定位");
        }*/

        Log.d(ID_TAG, "定位线程: " + Thread.currentThread().getId());
        synchronized(m_lock)
        {
            try
            {
                CleanLastLocation();
                Run(count);
                m_lock.wait();
            }
            catch(Exception e)
            {
                throw new RuntimeException(e);
            }
            finally
            {
                Stop();
            }
        }
        return m_lastLocation;
    }

    public NSLocationInfo GetLastLocation()
    {
        return m_lastLocation;
    }

    public void CleanLastLocation()
    {
        m_lastLocation = null;
    }

    /*
    在调用线程中执行
     */
    @Override
    public void onLocationChanged(@NonNull Location location)
    {
        Log.d(ID_TAG, "onLocationChanged线程: " + Thread.currentThread().getId());
        System.err.println(location);
        SetLastLocation(location);
        //if(null != location)
        {
            if(m_readOnce.get() > 0)
            {
                m_readOnce.decrementAndGet();
                if(m_readOnce.get() == 0)
                {
                    synchronized(m_lock)
                    {
                        m_lock.notifyAll();
                    }
                }
            }
        }
    }
}
