package org.kne.cloud.network.srv6;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.BindException;
import java.net.DatagramPacket;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;

import org.kne.cloud.network.ipv6.IPv6Address;
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6SegmentRoutingHeader;
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
import org.kne.cloud.network.ipv6.Neighbor;
import org.kne.cloud.network.klalb.KLALBVirtualRawSocket;
import org.kne.cloud.network.monitor.DelayMonitorData;
import org.kne.cloud.network.monitor.MonitorData;
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData;
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
import org.kne.membandboost.MembandBoost;

public class KLALBRoutingProtocol extends Thread{

	private static final boolean debug = false;

	private RouterInfo selfRouterInfo;
	private Map<IPv6Address, RouterInfo> netmap=new ConcurrentHashMap<>();
	
	
	private volatile Map<IPv6Address,Long>addresses;
	
	private volatile Map<IPv6Address, List<LinkDirection>> paths;
	
	
	

	
	
	
	
	
	public static final int DEFAULT_PORT=1001;

	public static final int DEFAULT_PROTOCOL_NUMBER=252;
	
	public static final long HOTSOPT_TIMEOUT = 1000000000;

	public static final int HOTSOPT_REPORT_INTERVAL = 1000000;
	private SRv6Router router;
	public SRv6Router getRouter() {
		return router;
	}
	public KLALBRoutingProtocol(SRv6Router router) {
		this.router=router;
	}
	
	//private ReentrantLock sendlock=new ReentrantLock();
	
	private long floodTimer=System.nanoTime();
	private long floodTimer2=System.nanoTime();
	private long requestTimer=System.nanoTime();
		private KLALBVirtualRawSocket ds = null;
		private ReentrantLock sendLock=new ReentrantLock();
		
	private Set<BiConsumer<SocketAddress,JsonDataPacket>>receivers=new CopyOnWriteArraySet<BiConsumer<SocketAddress,JsonDataPacket>>();
	
	public void addReceiver(BiConsumer<SocketAddress,JsonDataPacket> rec) {
		receivers.add(rec);
	}
	
	public void removeReceiver(BiConsumer<SocketAddress,JsonDataPacket> rec) {
		receivers.remove(rec);
	}
	
	@Override
	public void run() {
		Thread.currentThread().setName("KLALB路由协议接收线程");
		getSelfRouterInfo();
		try{
			ds=new KLALBVirtualRawSocket(router.getinLoopback(),router.getLocator().getAddress().toInet6Address(), DEFAULT_PROTOCOL_NUMBER);
			new Thread(()->{
				Thread.currentThread().setName("KLALB路由协议发送线程");
					
				while(true) {
				try {
					selfRouterInfo = getSelfRouterInfo();
					RouterInfo oslf=netmap.put(selfRouterInfo.getLocator().getAddress(), selfRouterInfo);
					noticeUpdate();
					/*if(oslf==null||(!selfRouterInfo.equals(oslf))) {
					long cur=System.nanoTime();
					if(cur-floodTimer2>5000000000L) {
						//System.out.println("update10");
						floodTimer2=cur;
						floodPacket(ds2, null, new RouterInfoPacket(selfRouterInfo,true));
					}
					}else {
					long cur=System.nanoTime();
					if(cur-floodTimer>60000000000L) {
						//System.out.println("update60");
						floodTimer=cur;
						floodPacket(ds2, null, new RouterInfoPacket(selfRouterInfo,true));
					}
					}*/
					
					long cur=System.nanoTime();
					if(cur-floodTimer>20000000000L) {
						if(debug)
						System.out.println("update60");
						floodTimer=cur;
						floodPacket( null, new RouterInfoPacket(selfRouterInfo,true,-1));
					}
					
					if(cur-floodTimer2>2000000000L) {
						if(debug)
						System.out.println("update1");
						floodTimer2=cur;
						floodPacket(null, new RouterInfoPacket(selfRouterInfo,true,router.getASN()));
					}
					
					//Set<Inet6Address> requestSet=new HashSet<>();
					for (Iterator<Entry<IPv6Address, RouterInfo>> iterator = netmap.entrySet().iterator(); iterator.hasNext();) {
						Entry<IPv6Address, RouterInfo> type = (Entry<IPv6Address, RouterInfo>) iterator.next();
						RouterInfo val=type.getValue();
						long timeout=30000000000L;
						if(val.getAsn()==router.getASN()) {
							timeout=2000000000L;
						}
						if(val.checkTimeOut(timeout)) {
							iterator.remove();
							noticeUpdate();
						}
						/*List<NeighborInfo> ads=val.getNeighborAddresses();
						for (Iterator<NeighborInfo> iterator2 = ads.iterator(); iterator2.hasNext();) {
							Inet6Address address=iterator2.next().getLocator().getAddress();
							//System.out.println(address);
							if(!netmap.containsKey(address)) {
								requestSet.add(address);
							}
							
						}*/
						
					}
					
					
					
					computeShortestPathIfUpdated();
					
					

					/*long cur2=System.nanoTime();
					if(cur2-requestTimer>1000000000L) {
						requestTimer=cur2;
						
					for (Iterator<Inet6Address> iterator = requestSet.iterator(); iterator.hasNext();) {
						Inet6Address inet6Address = (Inet6Address) iterator.next();
						
						writePacket(ds2, new RouterInfoRequestPacket( ), new InetSocketAddress(inet6Address, DEFAULT_PORT));

						if(debug)
						System.out.println("Request:"+inet6Address);
						
					}

					}*/
					
					for (Iterator<Entry<IPv6Address, HotspotAddressTimer>> iterator = hotspots.entrySet().iterator(); iterator.hasNext();) {
						Entry<IPv6Address, HotspotAddressTimer> type = (Entry<IPv6Address, HotspotAddressTimer>) iterator.next();
						//if(type.getValue().checkReportTime()) {
							//System.out.println("hotspot address:"+type.getKey());
							//writePacket(ds2, new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(type.getKey(), DEFAULT_PORT));
						//}
						if(type.getValue().checkTimeOut()) {
							iterator.remove();
						}
						
					}
					
						Thread.sleep(20);
					
				
				}  catch (InterruptedException e) {
						e.printStackTrace();
					}catch (IOException e1) {
						// TODO 自动生成的 catch 块
						e1.printStackTrace();
					}
				}
			}).start();
		while(true) {

			try {
			byte[]ca=MembandBoost.allocateUninitializedByteArray(65535);
			DatagramPacket dgp=new DatagramPacket(ca, ca.length);
			ds.receive(dgp);
			//System.out.println(Arrays.toString( Arrays.copyOf( dgp.getData(),dgp.getLength())));
			ByteArrayInputStream bi=new ByteArrayInputStream(dgp.getData(),0,dgp.getLength());
			KLALBRoutingProtocolPacket kp=KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(Channels.newChannel(bi));
			
			switch(kp.getType()) {
			case KLALBRoutingProtocolPacket.RINFO_REQ:
				RouterInfo rifr=netmap.get(router.getLocator().getAddress());
				if(debug)
				System.out.println("get Request from:"+dgp.getSocketAddress());
				if(rifr!=null) {
				writePacket( new RouterInfoPacket( rifr,false,-1), dgp.getSocketAddress());
				if(debug)
				System.out.println("response router info:"+rifr);
				}else {
					if(debug)
					System.out.println("router info is null!");
				}
				break;
			case KLALBRoutingProtocolPacket.RINFO:
				
				RouterInfoPacket rifp=(RouterInfoPacket) kp;
				RouterInfo rif=rifp.getRinfo();
				RouterInfo oldrif=netmap.get(rif.getLocator().getAddress());

				if(debug)
					System.out.println(rif);
				if(oldrif==null||oldrif.getCreateTime()<rif.getCreateTime()) {
					if(debug)
						System.out.println("update RouterInfo");
				netmap.put(rif.getLocator().getAddress(), rif);
				noticeUpdate();
				if(rifp.isFlood()) {
					floodPacket( dgp.getSocketAddress(), rifp);
				
				}
				
				}else {

					if(debug)
						System.out.println("dispose RouterInfo");
				}
				computeShortestPathIfUpdated();
				break;
			case KLALBRoutingProtocolPacket.JSON_DATA:
				JsonDataPacket data=(JsonDataPacket) kp;
				receivers.forEach((v)->{v.accept(dgp.getSocketAddress(),data);});
				break;
			default:
				break;
			}
			} catch (IOException e) {
			e.printStackTrace();
			}
		}
	} catch (SocketException e2) {
		e2.printStackTrace();
	}finally {
			if(ds!=null) {
				ds.close();
			}
	}
	}
	
	private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException {
		long asn=rifp.getASN();
		List<Neighbor>ln= router.getNeighbors();
		Set<InetSocketAddress>ist=new HashSet<InetSocketAddress>();
		for(Neighbor addresses :ln) {
				if(addresses.getLocator()==null)
					continue;
				InetSocketAddress isa=new InetSocketAddress(addresses.getLocator().getAddress().toInet6Address(),DEFAULT_PORT);
				if(!ist.add(isa)) {
					continue;
				}
				if(!isa.equals(except)) {
					if(asn==-1) {
					writePacket( rifp, isa);
					}else{
						RouterInfo nif= netmap.get( IPv6Address.valueOf( isa.getAddress()));
						if(nif!=null&&nif.getAsn()==asn) {
							writePacket( rifp, isa);
						}
					}
				}
		}
	}
	
	public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException {
		writePacket(pkt,dest);
	}
	
	private void writePacket(KLALBRoutingProtocolPacket pkt,SocketAddress dest) throws IOException {
		ByteArrayOutputStream bos=new ByteArrayOutputStream(65535);
		KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(Channels.newChannel(bos),pkt);
		byte[]to=bos.toByteArray();
		DatagramPacket dgpx=new DatagramPacket(to,to.length);
		dgpx.setSocketAddress(dest);
		sendLock.lock();
		try {
		ds.send(dgpx);
		}catch(BindException e) {
			e.printStackTrace();
			System.err.println("Cannot assign:"+dest);
		}finally {
			sendLock.unlock();
		}
	}
	
	private DijkstraAlgorithm algorithm=new SingleDijkstraAlgorithm();

	private ReentrantLock directionLock=new ReentrantLock();
	
	private volatile NetmapDirections directions;
	
	private static class NetmapDirections{
		
		public NetmapDirections(long[] direction, List<IPv6Address> rias,
				Map<IPv6Address, Long> direction_airs) {
			super();
			this.direction = direction;
			this.direction_rias = rias;
			this.direction_airs = direction_airs;
		}

		public NetmapDirections(long[] direction, List<Inet6Address> rias, Map<Inet6Address, Long> airs,Object obj) {
			this.direction = direction;
			this.direction_rias=new ArrayList<IPv6Address>();
			rias.forEach((addr)->{
				direction_rias.add(new IPv6Address(addr));
			});
			this.direction_airs=new HashMap<>();
			airs.forEach((k,v)->{
				direction_airs.put(new IPv6Address(k), v);
			});
		}

		private long[] direction;

		private List<IPv6Address> direction_rias;

		private Map<IPv6Address, Long> direction_airs;

		public long[] getDirection() {
			return direction;
		}

		public List<IPv6Address> getDirection_rias() {
			return direction_rias;
		}

		public Map<IPv6Address, Long> getDirection_airs() {
			return direction_airs;
		}
		
	}
	
	
	
	private volatile boolean updated=false;
	public void noticeUpdate() {
		updated=true;
	}
	private void computeShortestPathIfUpdated() {
		if(updated) {
		computeShortestPath();
		updated=false;
		}
	}
	
	private void computeShortestPath() {

		directionLock.lock();
		try {
		if(netmap.get(router.getLocator().getAddress())==null) {
			return;
		}
		Set<Entry<IPv6Address, RouterInfo>> s=netmap.entrySet();
		Map<IPv6Address,Long>airs=new HashMap<>(netmap.size()*2,0.4f);

		List<IPv6Address>rias=new ArrayList<>(netmap.size()+1);
		
		Map<IPv6Address,List< LinkDirection>>paths=new HashMap<>();
		long number=0;
		for(Entry<IPv6Address, RouterInfo> entry:s) {
			if(!airs.containsKey(entry.getKey())) {
			airs.put(entry.getKey(),number);
			rias.add( entry.getKey());
			number++;
			}
			List<NeighborInfo> ni= entry.getValue().getNeighborAddresses();
			for(NeighborInfo neighborInfo :ni) {
				IPv6Address ias2=neighborInfo.getLocator().getAddress();
				if(!airs.containsKey(ias2)) {
					airs.put(ias2,number);
					rias.add( ias2);
					number++;
					}
				List<LinkDirection>lp1=paths.get(entry.getKey());
				if(lp1==null) {
					paths.put(entry.getKey(), lp1=new ArrayList<>());
				}
				lp1.add(new LinkDirection(neighborInfo.getLocal(),neighborInfo.getNeighbor(),entry.getKey(), ias2, neighborInfo.getUploadDelay(),neighborInfo.getUploadDelayMin(),neighborInfo.getUploadSpeed(),neighborInfo.getUploadSpeedMax()));
				
				/*Set<LinkDirection>lp2=paths.get(ias2);
				if(lp2==null) {
					paths.put(ias2, lp2=new HashSet<>());
				}
				lp2.add( new LinkDirection(neighborInfo.getNeighbor(),neighborInfo.getLocal(),ias2,entry.getKey() , neighborInfo.getDownloadDelay(),neighborInfo.getDownloadDelayMin(),neighborInfo.getDownloadSpeed(),neighborInfo.getDownloadSpeedMax()));
				*/
			}
		}
		
		
		
		
		
		long[][]pointers=new long[(int) airs.size()][2];
		long heappos=0;
		long linknumber=0;
		for(Entry<IPv6Address, List<LinkDirection>> entry:paths.entrySet()) {
		/*for (Iterator<Entry<Inet6Address, Set<LinkDirection>>> iterator = paths.entrySet().iterator(); iterator.hasNext();) {
			Entry<Inet6Address, Set<LinkDirection>> entry = (Entry<Inet6Address, Set<LinkDirection>>) iterator.next();*/
			linknumber+=entry.getValue().size();
		}
		long[][]heap=new long[(int) (linknumber)][2];
		for (long i = 0; i < number; i++) {
			long heapindex=0;
			pointers[(int) i][0]=heappos;
			IPv6Address ia=rias.get((int) i);
			List<LinkDirection>lks=paths.get(ia);
			if(lks!=null)
				for(LinkDirection linkPath:lks) {
				/*
			for (Iterator<LinkDirection> iterator = lks.iterator(); iterator.hasNext();) {
			LinkDirection linkPath=iterator.next();*/
					heap[(int)(heappos+ heapindex)][0]=airs.get(linkPath.getToLocator());
					heap[(int) (heappos+heapindex)][1]=linkPath.getWeight();
					//heap[(int) (heappos+heapindex)][2]=linkPath.get
					//		heap[(int) (heappos+heapindex)][3]=0;
					heapindex++;
				
			}
				
			heappos+=heapindex;
			pointers[(int) i][1]=heapindex;
		}
		
		
		
		algorithm.setGraph(pointers,heap,airs.get(router.getLocator().getAddress()));
		algorithm.run();
		directions=new NetmapDirections(algorithm.getDirection(), rias, airs);
		addresses=airs;
		this.paths=paths;
		}finally {
			directionLock.unlock();
		}
		//System.out.println(Arrays.toString( algorithm.getDirection()));
	}
	public static class LinkDirection{
		private IPv6AddressGroup fromAddress; 
		private IPv6AddressGroup toAddress;
		private IPv6Address fromLocator; 
		private IPv6Address toLocator;
		private long delay;
		private long delayMin;
		private long speed;
		public long getSpeed() {
			return speed;
		}
		private long bandwidth;
		public IPv6AddressGroup getFromAddress() {
			return fromAddress;
		}
		public IPv6AddressGroup getToAddress() {
			return toAddress;
		}
		public long getDelay() {
			return delay;
		}
		public long getBandwidth() {
			return bandwidth;
		}
		
		public long getDelayMin() {
			return delayMin;
		}
		
		public LinkDirection(IPv6AddressGroup fromAddress, IPv6AddressGroup toAddress, IPv6Address fromLocator,
				IPv6Address toLocator, long delay, long delayMin, long speed, long bandwidth) {
			super();
			this.fromAddress = fromAddress;
			this.toAddress = toAddress;
			this.fromLocator = fromLocator;
			this.toLocator = toLocator;
			this.delay = delay;
			this.delayMin = delayMin;
			this.speed = speed;
			this.bandwidth = bandwidth;
		}
		@Override
		public String toString() {
			return "LinkDirection [fromAddress=" + fromAddress + ", toAddress=" + toAddress + ", fromLocator="
					+ fromLocator + ", toLocator=" + toLocator + ", delay=" + delay + ", delayMin=" + delayMin
					+ ", speed=" + speed + ", bandwidth=" + bandwidth + "]";
		}
		public IPv6Address getFromLocator() {
			return fromLocator;
		}
		@Override
		public int hashCode() {
			return Objects.hash(fromAddress, toAddress);
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			LinkDirection other = (LinkDirection) obj;
			return Objects.equals(fromAddress, other.fromAddress) && Objects.equals(toAddress, other.toAddress);
		}
		public IPv6Address getToLocator() {
			return toLocator;
		}
		public long getWeight() {
			return delay;
		}
	}
	private RouterInfo getSelfRouterInfo() {
		List<IPv6NetworkLink>links=router.getLinkTabel();
		Object[] nls=links.toArray();
		RouterInfo ri=new RouterInfo(System.currentTimeMillis(),router.getLocator(),router.getASN());
		for(int i=0;i<nls.length;i++) {
			IPv6NetworkLink nl=(IPv6NetworkLink) nls[i];
			if((!nl.isLoopBack())&&nl.isUp()) {
			List<Neighbor>neis=nl.getNeighborsInfo();
			for (Iterator<Neighbor> iteratorx = neis.iterator(); iteratorx.hasNext();) {
				Neighbor addresses = (Neighbor) iteratorx.next();
				long updelay=10000000000L;
				long downdelay=10000000000L;
				long updelayMin=10000000000L;
				long downdelayMin=10000000000L;
				long uploadspeed=1024L*1024;
				long downloadspeed=1024L*1024;
				long uploadspeedmax=1024L*1024;
				long downloadspeedmax=1024L*1024;
				MonitorData md=addresses.getMonitor();
				if(md!=null) {
					if(md instanceof DelayMonitorData) {
						updelay=((DelayMonitorData) md).getOutDelay();
						downdelay=((DelayMonitorData) md).getInDelay();

						if(md instanceof SpeedAndTrafficAndDelayMonitorDataImpl) {
						updelayMin=((SpeedAndTrafficAndDelayMonitorDataImpl) md).getOutDelayMin();
						downdelayMin=((SpeedAndTrafficAndDelayMonitorDataImpl) md).getInDelayMin();
						}
					}
					if(md instanceof SpeedAndTrafficMonitorData) {
						uploadspeed=((SpeedAndTrafficMonitorData) md).getOutSpeed();
						downloadspeed=((SpeedAndTrafficMonitorData) md).getInSpeed();
						if(md instanceof SpeedAndTrafficMonitorDataImpl) {
							SpeedAndTrafficMonitorDataImpl smd=(SpeedAndTrafficMonitorDataImpl) md;
						uploadspeedmax=smd.getOutSpeedMax();
						downloadspeedmax=smd.getInSpeedMax();
						}
					}
				}
				NeighborInfo ni=new NeighborInfo(nl.getAddressGroups().get(0),addresses.getAddress(),addresses.getLocator(),updelay ,downdelay,updelayMin ,downdelayMin ,uploadspeed ,downloadspeed,uploadspeedmax ,downloadspeedmax);
				ni.setContext(addresses);
				ri.getNeighborAddresses().add(ni);
				
			}
			}
		}
		//if(debug)
		//System.out.println(ri);
		return ri;
	}
	
	public Map<IPv6Address, Long> getAddresses() {
		return addresses;
	}
	public Map<IPv6Address, List<LinkDirection>> getPaths() {
		return paths;
	}
	public IPv6SegmentRoutingHeader createSegmentList(IPv6Address dest) {
		NetmapDirections directionsx=directions;
		if(directionsx==null) {
			return null;
		}
		Long dn=directionsx.getDirection_airs().get(dest);
		if(dn==null) {
			return null;
		}
		IPv6SegmentRoutingHeader segs=new IPv6SegmentRoutingHeader();
		List<IPv6Address>segments=segs.getAddresses();
			while(true) {
				long idx=directionsx.getDirection()[(int) dn.longValue()];
				if(idx==-1) {
					return null;
				}
				if(idx==dn) {
			         segs.  resetSegmentPos();
					return segs;
				}
				segments.add(directionsx.getDirection_rias().get(dn.intValue()));
				dn=idx;
			}
	}
	public long getDevicesFound() {
		return netmap.size();
	}
	
	private static class HotspotAddressTimer{
		private long putTime=System.nanoTime();
		private long reportTime =System.nanoTime();
		public boolean checkTimeOut() {
			return System.nanoTime()-putTime>HOTSOPT_TIMEOUT;
		}
		public boolean checkReportTime() {
			long cu = System.nanoTime();
		if (cu - reportTime > HOTSOPT_REPORT_INTERVAL) {
			reportTime = cu;
			return true;
		} else {
			return false;
		}
		}
		public void refreshTimeout() {
			putTime=System.nanoTime();
		}
	}
	
	private Map<IPv6Address, HotspotAddressTimer> hotspots=new ConcurrentHashMap<>();
	public void putHotspotAddress(IPv6Address iPv6Address) {
		if(true) {
		HotspotAddressTimer hat=hotspots.get(iPv6Address);
		if(hat==null) {
		hotspots.put(iPv6Address,hat= new HotspotAddressTimer());
		}else {
			hat.refreshTimeout();
		}
		if(hat.checkReportTime()) {
			//System.out.println("hotspot address:"+sourceAddress);
		/*	try {
				writePacket( new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(iPv6Address.toInet6Address(), DEFAULT_PORT));
			} catch (IOException e) {
				e.printStackTrace();
			}*/
		}
		}
	}
	private Map<IPv6Address,Long> toIpBandwidth=new ConcurrentHashMap<IPv6Address,Long>();

	public void updateTotalRequestBandwidth(IPv6Address targetaAddress, Long treq) {
		Objects.requireNonNull(targetaAddress);
		//System.out.println("到"+targetaAddress.getHostAddress()+"请求带宽更新："+treq);
		if(treq<=0) {
			if(toIpBandwidth.remove(targetaAddress)!=null) {
				noticeUpdate();
			}
		}else {
			Long old=toIpBandwidth.put(targetaAddress, treq);
			if(old==null||old.longValue()!=treq.longValue()) {
				noticeUpdate();
			}
		}
	}
	public IPv6Address getDijkstraPrevNode(IPv6Address text) {
		NetmapDirections directionsx=directions;
		if(directionsx==null)
			return null;
		Long l=directionsx.getDirection_airs().get(text);
		if(l==null)
			return null;
		long number= l;
		long prev= directionsx.getDirection()[(int)number];
		if(prev==-1) {
			return null;
		}
		return directionsx.getDirection_rias().get((int) prev);
	}

}
