package overlay;

import android.content.Context;
import android.graphics.Color;

import com.amap.api.maps.AMap;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.TMC;
import com.amap.api.services.route.TruckPath;
import com.amap.api.services.route.TruckStep;
import com.amap.map3d.demo.R;
import com.amap.map3d.demo.util.AMapUtil;

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


/**
 * 导航路线图层类。
 */
public class TruckRouteColorfulOverLay extends RouteOverlay{

	private TruckPath truckPath;
    private List<LatLonPoint> throughPointList;
    private List<Marker> throughPointMarkerList = new ArrayList<Marker>();
    private boolean throughPointMarkerVisible = true;
    private List<TMC> tmcs;
    private PolylineOptions mPolylineOptions;
    private Context mContext;
    private boolean isColorfulline = true;
    private float mWidth = 17;
    private List<LatLng> mLatLngsOfPath;

	public void setIsColorfulline(boolean iscolorfulline) {
		this.isColorfulline = iscolorfulline;
	}

	/**
     * 根据给定的参数,构造一个导航路线图层类对象。
     *
     * @param amap      地图对象。
     * @param path 导航路线规划方案。
     * @param context   当前的activity对象。
     */
    public TruckRouteColorfulOverLay(Context context, AMap amap, TruckPath path,
                                     LatLonPoint start, LatLonPoint end, List<LatLonPoint> throughPointList) {
    	super(context);
    	mContext = context; 
        mAMap = amap; 
        this.truckPath = path;
        startPoint = AMapUtil.convertToLatLng(start);
        endPoint = AMapUtil.convertToLatLng(end);
        this.throughPointList = throughPointList;
    }

    @Override
    public float getRouteWidth() {
        return mWidth;
    }

    /**
     * 设置路线宽度
     *
     * @param mWidth 路线宽度,取值范围:大于0
     */
    public void setRouteWidth(float mWidth) {
        this.mWidth = mWidth;
    }

    /**
     * 添加驾车路线添加到地图上显示。
     */
	public void addToMap() {
		initPolylineOptions();
        try {
            if (mAMap == null) {
                return;
            }

            if (mWidth == 0 || truckPath == null) {
                return;
            }
            mLatLngsOfPath = new ArrayList<LatLng>();
            tmcs = new ArrayList<TMC>();
            List<TruckStep> steps = truckPath.getSteps();
            for (TruckStep step : steps) {
                List<LatLonPoint> latlonPoints = step.getPolyline();
                List<TMC> tmclist = step.getTMCs();
                tmcs.addAll(tmclist);

                for (LatLonPoint latlonpoint : latlonPoints) {
                	mPolylineOptions.add(convertToLatLng(latlonpoint));
                	mLatLngsOfPath.add(convertToLatLng(latlonpoint));
				}
            }
            if (startMarker != null) {
                startMarker.remove();
                startMarker = null;
            }
            if (endMarker != null) {
                endMarker.remove();
                endMarker = null;
            }
            addStartAndEndMarker();
            addThroughPointMarker();
            if (isColorfulline && tmcs.size()>0 ) {
            	colorWayUpdate(tmcs);
			}else {
				showPolyline();
			}            
            
        } catch (Throwable e) {
        	e.printStackTrace();
        }
    }

    /**
     * 初始化线段属性
     */
    private void initPolylineOptions() {

        mPolylineOptions = null;

        mPolylineOptions = new PolylineOptions();
        mPolylineOptions.color(getDriveColor()).width(getRouteWidth());
    }

    private void showPolyline() {
        addPolyLine(mPolylineOptions);
    }
    

    /**
     * 根据不同的路段拥堵情况展示不同的颜色
     *
     * @param tmcSection
     */
    private void colorWayUpdate(List<TMC> tmcSection) {
        if (mAMap == null) {
            return;
        }
        if (mLatLngsOfPath == null || mLatLngsOfPath.size() <= 0) {
            return;
        }
        if (tmcSection == null || tmcSection.size() <= 0) {
            return;
        }
        int j = 0;
        LatLng startLatLng = mLatLngsOfPath.get(0);
        LatLng endLatLng = null;
        double segmentTotalDistance = 0;
        TMC segmentTrafficStatus;
        List<LatLng> tempList = new ArrayList<LatLng>();
        //画出起点到规划路径之间的连线
        addPolyLine(new PolylineOptions().add(startPoint, startLatLng)
				.setDottedLine(true));
        //终点和规划路径之间连线
        addPolyLine(new PolylineOptions().add(mLatLngsOfPath.get(mLatLngsOfPath.size()-1), 
        		endPoint).setDottedLine(true));
        for (int i = 0; i < mLatLngsOfPath.size() && j < tmcSection.size(); i++) {
            segmentTrafficStatus = tmcSection.get(j);
            endLatLng = mLatLngsOfPath.get(i);
            double distanceBetweenTwoPosition = calculateDistance(startLatLng, endLatLng);
            segmentTotalDistance = segmentTotalDistance + distanceBetweenTwoPosition;
            if (segmentTotalDistance > segmentTrafficStatus.getDistance() + 1) {
                double toSegDis = distanceBetweenTwoPosition - (segmentTotalDistance - segmentTrafficStatus.getDistance());
                LatLng middleLatLng = getPointForDis(startLatLng, endLatLng, toSegDis);
                tempList.add(middleLatLng);
                startLatLng = middleLatLng;
                i--;
            } else {
                tempList.add(endLatLng);
                startLatLng = endLatLng;
            }
            if (segmentTotalDistance >= segmentTrafficStatus.getDistance() || i == mLatLngsOfPath.size() - 1) {
                if (j == tmcSection.size() - 1 && i < mLatLngsOfPath.size() - 1) {
                    for (i++; i < mLatLngsOfPath.size(); i++) {
                        LatLng lastLatLng = mLatLngsOfPath.get(i);
                        tempList.add(lastLatLng);
                    }
                }
                j++;
                if (segmentTrafficStatus.getStatus().equals("畅通")) {
                	addPolyLine((new PolylineOptions()).addAll(tempList)
                            .width(mWidth).color(Color.GREEN));
				} else if (segmentTrafficStatus.getStatus().equals("缓行")) {
					addPolyLine((new PolylineOptions()).addAll(tempList)
                            .width(mWidth).color(Color.YELLOW));
				} else if (segmentTrafficStatus.getStatus().equals("拥堵")) {
					addPolyLine((new PolylineOptions()).addAll(tempList)
                             .width(mWidth).color(Color.RED));
				} else if (segmentTrafficStatus.getStatus().equals("严重拥堵")) {
					addPolyLine((new PolylineOptions()).addAll(tempList)
                            .width(mWidth).color(Color.parseColor("#990033")));
				} else {
					addPolyLine((new PolylineOptions()).addAll(tempList)
                            .width(mWidth).color(Color.parseColor("#537edc")));
				}
                tempList.clear();
                tempList.add(startLatLng);
                segmentTotalDistance = 0;
            }
           if (i == mLatLngsOfPath.size() - 1) {
        	   addPolyLine(new PolylineOptions().add(endLatLng, endPoint)
        			   .setDottedLine(true));
		} 
        }
    }
    
    public LatLng convertToLatLng(LatLonPoint point) {
        return new LatLng(point.getLatitude(),point.getLongitude());
  }
    
    /**
     * @param driveStep
     * @param latLng
     */
    private void addLimitMarker(TruckStep step, LatLng latLng) {

//        addStationMarker(new MarkerOptions()
//                .position(latLng)
//                .title("\u65B9\u5411:" + driveStep.getAction()
//                        + "\n\u9053\u8DEF:" + driveStep.getRoad())
//                .snippet(driveStep.getInstruction()).visible(nodeIconVisible)
//                .anchor(0.5f, 0.5f).icon(getDriveBitmapDescriptor()));
    }

    @Override
    protected LatLngBounds getLatLngBounds() {
        LatLngBounds.Builder b = LatLngBounds.builder();
        b.include(new LatLng(startPoint.latitude, startPoint.longitude));
        b.include(new LatLng(endPoint.latitude, endPoint.longitude));
        if (this.throughPointList != null && this.throughPointList.size() > 0) {
            for (int i = 0; i < this.throughPointList.size(); i++) {
                b.include(new LatLng(
                        this.throughPointList.get(i).getLatitude(),
                        this.throughPointList.get(i).getLongitude()));
            }
        }
        return b.build();
    }

    public void setThroughPointIconVisibility(boolean visible) {
        try {
            throughPointMarkerVisible = visible;
            if (this.throughPointMarkerList != null
                    && this.throughPointMarkerList.size() > 0) {
                for (int i = 0; i < this.throughPointMarkerList.size(); i++) {
                    this.throughPointMarkerList.get(i).setVisible(visible);
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
    
    private void addThroughPointMarker() {
        if (this.throughPointList != null && this.throughPointList.size() > 0) {
            LatLonPoint latLonPoint = null;
            for (int i = 0; i < this.throughPointList.size(); i++) {
                latLonPoint = this.throughPointList.get(i);
                if (latLonPoint != null) {
                    throughPointMarkerList.add(mAMap
                            .addMarker((new MarkerOptions())
                                    .position(
                                            new LatLng(latLonPoint
                                                    .getLatitude(), latLonPoint
                                                    .getLongitude()))
                                    .visible(throughPointMarkerVisible)
                                    .icon(getThroughPointBitDes())
                                    .title("\u9014\u7ECF\u70B9")));
                }
            }
        }
    }
    
    private BitmapDescriptor getThroughPointBitDes() {
    	return BitmapDescriptorFactory.fromResource(R.drawable.amap_through);
       
    }

    /**
     * 获取两点间距离
     *
     * @param start
     * @param end
     * @return
     */
    public static int calculateDistance(LatLng start, LatLng end) {
        double x1 = start.longitude;
        double y1 = start.latitude;
        double x2 = end.longitude;
        double y2 = end.latitude;
        return calculateDistance(x1, y1, x2, y2);
    }

    public static int calculateDistance(double x1, double y1, double x2, double y2) {
        final double NF_pi = 0.01745329251994329; // 弧度 PI/180
        x1 *= NF_pi;
        y1 *= NF_pi;
        x2 *= NF_pi;
        y2 *= NF_pi;
        double sinx1 = Math.sin(x1);
        double siny1 = Math.sin(y1);
        double cosx1 = Math.cos(x1);
        double cosy1 = Math.cos(y1);
        double sinx2 = Math.sin(x2);
        double siny2 = Math.sin(y2);
        double cosx2 = Math.cos(x2);
        double cosy2 = Math.cos(y2);
        double[] v1 = new double[3];
        v1[0] = cosy1 * cosx1 - cosy2 * cosx2;
        v1[1] = cosy1 * sinx1 - cosy2 * sinx2;
        v1[2] = siny1 - siny2;
        double dist = Math.sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);

        return (int) (Math.asin(dist / 2) * 12742001.5798544);
    }


    //获取指定两点之间固定距离点
    public static LatLng getPointForDis(LatLng sPt, LatLng ePt, double dis) {
        double lSegLength = calculateDistance(sPt, ePt);
        double preResult = dis / lSegLength;
        return new LatLng((ePt.latitude - sPt.latitude) * preResult + sPt.latitude, (ePt.longitude - sPt.longitude) * preResult + sPt.longitude);
    }
    /**
     * 去掉DriveLineOverlay上的线段和标记。
     */
    @Override
    public void removeFromMap() {
        try {
            super.removeFromMap();
            if (this.throughPointMarkerList != null
                    && this.throughPointMarkerList.size() > 0) {
                for (int i = 0; i < this.throughPointMarkerList.size(); i++) {
                    this.throughPointMarkerList.get(i).remove();
                }
                this.throughPointMarkerList.clear();
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}