/* 
 * PROJECT: NyARToolkit(Extension)
 * --------------------------------------------------------------------------------
 * The NyARToolkit is Java edition ARToolKit class library.
 * Copyright (C)2008-2009 Ryo Iizuka
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For further information please contact.
 *	http://nyatla.jp/nyatoolkit/
 *	<airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
 * 
 */
using System.Collections.Generic;
using jp.nyatla.nyartoolkit.cs.core;
namespace jp.nyatla.nyartoolkit.cs.markersystem.utils
{


    public class ARMarkerList : System.Collections.Generic.List<ARMarkerList.Item>
    {
	    /**
	     * このクラスは、ARマーカの検出結果を保存するデータクラスです。
	     */
	    public class Item : TMarkerData
	    {
		    /** MK_ARの情報。比較のための、ARToolKitマーカを格納します。*/
		    public NyARMatchPatt_Color_WITHOUT_PCA matchpatt;
		    /** MK_ARの情報。検出した矩形の格納変数。マーカの一致度を格納します。*/
		    public double cf;
		    public int patt_w;
		    public int patt_h;
		    /** MK_ARの情報。パターンのエッジ割合。*/
		    public int patt_edge_percentage;
		    /** */
		    public Item(NyARCode i_patt,int i_patt_edge_percentage,double i_patt_size)
		    {
			    //base();
			    this.matchpatt=new NyARMatchPatt_Color_WITHOUT_PCA(i_patt);
			    this.patt_edge_percentage=i_patt_edge_percentage;
			    this.marker_offset.setSquare(i_patt_size);
			    this.patt_w=i_patt.getWidth();
			    this.patt_h=i_patt.getHeight();
			    return;
		    }		
	    }	
        /**
         * 
         */
        private double _configense_th = 0.5;
        private readonly NyARMatchPattResult _patt_result = new NyARMatchPattResult();
        private readonly MultiResolutionPattProvider _mpickup = new MultiResolutionPattProvider();
        private ARMarkerSortList _mkmap;
        public ARMarkerList()
        {
            this._mkmap = new ARMarkerSortList();//初期値1マーカ
            return;
        }
        /**
         * このAdd以外使わないでね。
         */
        public void add(ARMarkerList.Item i_e)
        {
            //マッチテーブルのサイズを調整
            int s = this.Count + 1;
            while (this._mkmap.getLength() < s * s)
            {
                this._mkmap.append();
            }
            base.Add(i_e);
        }
        /**
         * マーカの一致敷居値を設定する。
         */
        public void setConficenceTh(double i_th)
        {
            this._configense_th = i_th;
        }
        /**
         * o_targetsに、敷居値を越えたターゲットリストを返却する。
         * @param i_pix_drv
         * @param i_vertex
         * @param o_targets
         * @return
         * @ 
         */
        public bool update(INyARPerspectiveCopy i_pix_drv, SquareStack.Item i_sq)
        {
            //sq_tmpに値を生成したかのフラグ
            bool is_ganalated_sq = false;
            for (int i = this.Count - 1; i >= 0; i--)
            {
                ARMarkerList.Item target = this[i];
                //解像度に一致する画像を取得
                NyARMatchPattDeviationColorData diff = this._mpickup.getDeviationColorData(target, i_pix_drv, i_sq.ob_vertex);
                //マーカのパターン解像度に一致したサンプリング画像と比較する。
                if (!target.matchpatt.evaluate(diff, this._patt_result))
                {
                    continue;
                }
                //敷居値をチェック
                if (this._patt_result.confidence < this._configense_th)
                {
                    continue;
                }
                //マーカマップへの追加対象か調べる。
                ARMarkerSortList.Item ip = this._mkmap.getInsertPoint(this._patt_result.confidence);
                if (ip == null)
                {
                    continue;
                }
                //マーカマップアイテムの矩形に参照値を設定する。
                ip = this._mkmap.insertFromTailBefore(ip);
                ip.cf = this._patt_result.confidence;
                ip.dir = this._patt_result.direction;
                ip.marker = target;
                ip.ref_sq = i_sq;
                is_ganalated_sq = true;
            }
            return is_ganalated_sq;
        }
        /**
         * @param i_num_of_markers
         * マーカの個数
         */
        public void prepare()
        {
            //マッチングテーブルをリセット
            this._mkmap.reset();

            //検出のために初期値設定
            for (int i = this.Count - 1; i >= 0; i--)
            {
                ARMarkerList.Item target = this[i];
                if (target.life > 0)
                {
                    target.lost_count++;
                }
            }
        }
        public void finish()
        {
            //一致率の最も高いアイテムを得る。
            ARMarkerSortList.Item top_item = this._mkmap.getTopItem();
            //アイテムを検出できなくなるまで、一致率が高い順にアイテムを得る。
            while (top_item != null)
            {
                //検出したアイテムのARmarkerIndexのデータをセット
                ARMarkerList.Item target = top_item.marker;
                if (target.lost_count > 0)
                {
                    //未割当のマーカのみ検出操作を実行。
                    target.cf = top_item.cf;
                    target.lost_count = 0;//消失カウンタをリセット
                    target.life++;      //ライフ値を加算
                    target.sq = top_item.ref_sq;
                    target.sq.rotateVertexL(4 - top_item.dir);
                    NyARIntPoint2d.shiftCopy(top_item.ref_sq.ob_vertex, target.tl_vertex, 4 - top_item.dir);
                    target.tl_center.setValue(top_item.ref_sq.center2d);
                    target.tl_rect_area = top_item.ref_sq.rect_area;
                }
                //基準アイテムと重複するアイテムを削除する。
                this._mkmap.disableMatchItem(top_item);
                top_item = this._mkmap.getTopItem();
            }
            //消失カウンタが敷居値を越えたら、lifeを0にする。
        }
    }
}