;(function($){

	$(window).load(function(event){
		// Form manipulation
		var jForm = $('form#noTransition');
		((0 < jForm.size()) ? jForm : $('form:first')).formMan();
	});

	// From http://groups.google.com/group/jquery-en/browse_thread/thread/df28d794de5a9c4e/d53038a86929c34f?pli=1
	$.fn.sort = function() {return this.pushStack( $.makeArray( [].sort.apply( this, arguments ) ) );}; 

	// Form manipulation
	$.fn.formMan = function(opts) {
		var settings = {
			sFMsgCls	: "errmsg",
			sMsgSaved	: "\u767b\u9332\u3057\u307e\u3057\u305f\u3002", // 登録しました。のメッセージ
			sKeepCls	: "unreplaceable",
			onRowPlace: null
		};
		$.extend(settings, $.hybs.defaults, opts || {});

		return this.each(function() {
			var oForm = this;

			// 画面の行入換えの共通関数
			// (入れ替え元の行オブジェクト, 入れ替え先のHTML, ハイライトにするか)
			var replaceRow = function (jTr, sRowHtml, bHiLight) {
				var sSrc, sClass;
				sSrc = jTr.find('.' + settings.sKeepCls).attr('src');
				sClass = jTr.find('.' + settings.sKeepCls).attr('class');
				//jTr.html(sRowHtml);
				jTr = $(sRowHtml).replaceAll(jTr);
				// Replace part of the inserted content
				if(settings.onRowPlace) {
					settings.onRowPlace(sHybsCmd, jTr);
				}
				else {
					if(sSrc) jTr.find('.' + settings.sKeepCls).attr('src', sSrc);
					if(sClass) jTr.find('.' + settings.sKeepCls).removeClass().addClass(sClass);
				}
				if(bHiLight && !jTr.hasClass('row_hilight')) jTr.removeClass('row_0 row_1').addClass('row_hilight');
				return jTr;
			}

			//viewTableが存在するかつ行が1行以上ある時のデータ処理
			var operateOnRows = function (jTab, jTr1st, sHybsCmd, data) {
				// チェックされたチェックボックスの一覧
				//var jChks = $form.find('input[name=' + settings.sHybsSel + ']:checked');
				var jChks = jTab.find('input[name=' + settings.sHybsSel + ']:checked');
				var bHasChecked = ( jChks.length>0 );

				// trにrow_0 or row_1 等がある場合は、1番目のtrオブジェクト(HTMLTable), それ以外は、1番目のtbodyオブジェクト(HTMLCustomTable)
				var jTBodyTr = $.hybs.getHybsTr(jTr1st);
				var bUnitRow = jTBodyTr.is("tr");

				// ※変更要!!!!!!!!!!!
				// 改廃Cは0番目の列の番号
				var nKhColId = 0;
				// Noの列の番号
				var nNoColId = $.hybs.getNoColId(jTab);

				// 削除行の配列,最初の削除行の上のオブジェクト
				var aDelRid =[], jTrFix2;

				var jTrs;
				switch(sHybsCmd) {
				case settings.sCmdInsert:
				case settings.sCmdInsertOne: // 5.1.5.0 (2010/04/01)
				case settings.sCmdCopy:
				case settings.sCmdModify:
				case settings.sCmdDelete:
				case settings.sCmdUndo:
				case settings.sCmdEntry:
						// Entry以外はチェックボックスがある行のみ処理
						// チェックがない場合は、1行目を強制的にセット(追加・複写時のため)
						if(bUnitRow) { jTrs = (bHasChecked) ? jChks.parents('tr') : jTBodyTr; }
						else		 { jTrs = (bHasChecked) ? jChks.parents('tbody') : jTBodyTr; }
						break;
				}

				// ridでソート
				jTrs.sort(function(a, b) {return a.getAttribute(settings.sHybsRid, 2) - b.getAttribute(settings.sHybsRid, 2);}); 

				var bPassOnce = false;
				var match, re, sText;
				// 処理行のループ
				jTrs.each(function(index) {

					// 5.1.5.0 (2010/04/01)
					if( sHybsCmd == settings.sCmdInsertOne && index < jTrs.length -1 ) { return; }

					var jTr = $(this);
					//画面初期化かつ画面に追加行がある時、サーバーから帰ってきたデータがなかったので、ここに特別処理
					if(sHybsCmd == settings.sCmdUndo && 'A' == jTr.attr(settings.sHybsKh)) {
						// 最初の削除行のみセット
						if(!jTrFix2) { jTrFix2 = jTr.prev(); }
						aDelRid.push(parseInt(jTr.attr(settings.sHybsRid)));
						jTr.remove();
					}
					else {
						//画面に処理行がある時に、一回だけの処理をここに行う
						if(!bPassOnce) {
							if(bUnitRow) {
								// 処理するHTML全体を取得(<tr> </tr> ･･･ <tr> </tr> )
								// 2009/06/29 tbody入れ子解消
								//match = /<tbody>([\S\s]*)<\/tbody>/m.exec(data);
								match = /(<tbody[^>]*>[\S\s]*<\/tbody>)/m.exec(data);
								re = /(<tr[^>]*?>[\S\s]*?<\/tr>)/m;
							}
							else {
								// 処理するHTML全体を取得(<tbody> </tbody> ･･･ <tbody> </tbody> )
								// 2009/06/29 tbody入れ子解消
								//match = /<tbody>([\S\s]*)<\/tbody>/m.exec(data);
								match = /(<tbody[^>]*>[\S\s]*<\/tbody>)/m.exec(data);
								re = /(<tbody[^>]*?>[\S\s]*?<\/tbody>)/m;
							}

							if(match) {
								// 処理する全体のHTML(複数行)
								sText = match[1];
							}
							bPassOnce = true;
						}

						if(sText) {
							// 1行分取得
							match = re.exec(sText);
							if(match) {
								// 行自動focus用のタグを削除
								var sRowText = match[1].replace(/<a href="#top"[^>]*><\/a>/m, "");
								
								// 5.0.0.4 (2009/10/01) 最終行に戻ってしまう問題に対応するため、チェックボックスの兄弟要素としてSEL_ROWをhiddenで追加する。
								var _checkedRow = jTr.find('input[name=' + settings.sHybsSel + ']:first').val();
								if( ! _checkedRow ){ _checkedRow = 0; } // 取れない時は0行目
								if( sHybsCmd == settings.sCmdCopy && bHasChecked ) { _checkedRow++; } // commandがcopyで、チェックがある場合は+1する。
								var rowSel_reg = new RegExp('(<input type=\"checkbox\" name=\"' + settings.sHybsSel + '\"[^>]*>)','m');
								sRowText = sRowText.replace( rowSel_reg , '$1<input type=\"hidden\" name=\"' + settings.sSelRow + '\" value=\"' + _checkedRow + '\" />' );

								switch(sHybsCmd) {
								case settings.sCmdInsert:
								case settings.sCmdInsertOne: // 5.1.5.0 (2010/04/01)
								case settings.sCmdCopy:
									// 行選択されている場合は選択行の後ろに、選択されていない場合は、選択行の前に挿入
									var jTrNew = (bHasChecked) ? $(sRowText).insertAfter(jTr) : $(sRowText).insertBefore(jTr);
									jTrNew.removeClass('row_0 row_1').addClass('row_hilight');
									if(0 <= nNoColId) { jTrNew.find('td:eq(' + nNoColId + ')').empty(); }

									// 既に編集中の行に対して複写等をした場合は、元の行のチェックを外さない
									if(!jTr.attr(settings.sHybsKh)) {
										jTr.find('input[name=' + settings.sHybsSel + ']:first').removeAttr('checked');
									}
									break;
								case settings.sCmdModify:
								case settings.sCmdDelete:
									// 改廃Cがある場合は何もしない
									if(!jTr.attr(settings.sHybsKh)) {
										// 変更行に番号が出力されれているか
										var sNoCol = ((0 <= nNoColId) ? jTr.find('td:nth(' + nNoColId + ')').text() : "");
										jTr = replaceRow(jTr, sRowText, true);

										// 追加→登録→変更とした場合に行番号を出さないようにしている)
										if((0 <= nNoColId) && !sNoCol) jTr.find('td:nth(' + nNoColId + ')').empty();
									}
									break;
								case settings.sCmdEntry:
									var cChgType = jTr.attr(settings.sHybsKh) || "";
									// チェックした行番号があるかないかを保存
									var sNoCol = ((0 <= nNoColId) ? jTr.find('td:nth(' + nNoColId + ')').text() : "");

									// 行がチェックされているか
									var bChecked = jTr.find('input[name=' + settings.sHybsSel + ']:first').attr('checked');
									jTr = replaceRow(jTr, sRowText, true);

									if(bChecked) {
										switch(cChgType) {
											case "D":
												// 最初の削除行のみセット
												if(!jTrFix2) { jTrFix2 = jTr.prev(); }
												aDelRid.push(parseInt(jTr.attr(settings.sHybsRid)));
												jTr.remove();
												break;
											case "A":
											case "C":
												// 表示とtr or tbody の改廃Cの属性を削除
												if(0 <= nKhColId) jTr.find('td:eq(' + nKhColId + ')').empty();
												jTr.removeAttr(settings.sHybsKh);

												// チェックを外す
												jTr.find('input[name=' + settings.sHybsSel + ']:first').removeAttr('checked');

												// 追加→登録→変更とした場合に行番号を出さないようにしている
												if((0 <= nNoColId) && !sNoCol) jTr.find('td:nth(' + nNoColId + ')').empty();
												break;
										}
									}

									// Output saved message
									$('.' + settings.sFMsgCls).html(settings.sMsgSaved);

									break;
								case settings.sCmdUndo:
									var cChgType = jTr.attr(settings.sHybsKh) || "";
									// チェックした行番号があるかないかを保存
									var sNoCol = ((0 <= nNoColId) ? jTr.find('td:nth(' + nNoColId + ')').text() : "");
									jTr = replaceRow(jTr, sRowText, true);

									// Clear changed type
									switch(cChgType) {
										case "C":
										case "D":
											// 改廃C削除 & チェック外す
											if(0 <= nKhColId) jTr.find('td:eq(' + nKhColId + ')').empty();
											jTr.removeAttr(settings.sHybsKh);
											jTr.find('input[name=' + settings.sHybsSel + ']:first').removeAttr('checked');
											// 追加→登録→変更とした場合に行番号を出さないようにしている
											if((0 <= nNoColId) && !sNoCol) jTr.find('td:nth(' + nNoColId + ')').empty();

											break;
											// Aの場合、上に既に特別処理をした
									}

									break;
								}
								sText = sText.substr(match.index + match[0].length);
							}
						}
					}
				});
				// 画面に削除行がある時に、画面の行番号の振り直し
				if(jTrFix2) {
					var jRun;
					// 行がtrの場合 ? trの親がtbodyか? : (tbodyの場合)子供がtrか -> これで削除行の上の行がデータ行か判断
					var bHasTrFix = jTrFix2[0]
									 && (bUnitRow ? jTrFix2.parent().is('tbody') : jTrFix2.children(':first').is('tr'));
					// 削除行の次から
					if(bHasTrFix) {
						jRun = jTrFix2.next();
					}
					// 初めから
					else {
							jTBodyTr = jTab.find('tbody tr:first');
							jRun = bUnitRow ? jTBodyTr : jTBodyTr.parent();
					}
					//削除した行のridをソートする
					aDelRid.sort();
					var nDelLen = aDelRid.length;
					while(jRun[0]) {
						var nDiff = 0, nRidRun = parseInt(jRun.attr(settings.sHybsRid));

						//該当行の前に、何行が削除されたかを確認する
						for(var iCntUp = (nDelLen - 1); 0 <= iCntUp; iCntUp--)
							{if(nRidRun > aDelRid[iCntUp]) {nDiff = ++iCntUp; break;}}
						if(nDiff > 0) {
							nRidRun -= nDiff;
							//画面に出したチェックボックスを振り直す
							//チェックボックスのvalue,id tr or tbodyのrid
							jRun.attr(settings.sHybsRid, nRidRun)
									.find('input[name=' + settings.sHybsSel + ']:first')
									.attr({id:'cb' + nRidRun, value:nRidRun});

							//※行番号!!!!! 画面に出した行番号をも振り直す
							if(0 <= nNoColId) {
								var jNoCol = jRun.find('td:nth(' + nNoColId + ')');
								if(jNoCol.text()) jNoCol.text(nRidRun+1);
							}
						}

						jRun = jRun.next();
					}

					//画面行の削除で行がなければ、残っていたtbodyも消す
					$('tbody:first:not(:has(tr:first-child))', jTab).remove();
				}
				// resize view range
//				if(bPassOnce) { jTab.resizeView(); }
				if( jTrs.length > 0 ) {
					jTab.resizeView();
					buttonControl(); // 4.3.4.6 (2009/01/15)
				}
			}

			//viewTableが存在する(ヘッダーのみ)時のデータ追加
			var addToNoTBody = function (jTab, sCmd, data) {
				// There exists no tbody contents on the screen
				// 5.1.5.0 (2010/04/01)
				if(sCmd == settings.sCmdInsert || sCmd == settings.sCmdInsertOne || sCmd == settings.sCmdCopy) {
					//画面にヘッダだけの場合、追加可能にする
					var match = /(?:<tbody>)?\r?\n?(<tbody>[\S\s]*<\/tbody>)\r?\n?(?:<\/tbody>)?/m.exec(data);
					if(match) {
						// Delete <a href="#top" name="h_fcs" id="h_fcs" ></a> between tr and td
						var sText = $.trim(match[1].replace(/<a href="#top"[^>]*><\/a>/m, ""));
						if(sText) {
							jTab.append(sText)
							jTab.resizeView();
							buttonControl(); // 4.3.4.6 (2009/01/15)
						};
					}
				}
			}

			//viewTableが存在しない時のデータ追加
			var addToNoTable = function (jForm, sCmd, data) {
				// 5.1.5.0 (2010/04/01)
				if(sCmd == settings.sCmdInsert || sCmd == settings.sCmdInsertOne || sCmd == settings.sCmdCopy) {
					// 検索してデータがまったくなかったら、追加が可能にする
					var match = /(<div onclick="hilightRow)|(\[\d+ - \d+\]\/\[\d+\])|(<div id="divPos)|(<table id="viewTable)/m.exec(data);
					if(match) {
						var sHLRow = "hilightRow";
						var sText = match[1];
						match = /([\S\s]*<table[^>]*?>[\S\s]*<\/table>[\S\s]*)/m.exec(data.substr(match.index));
						if(match) {
							// 画面の操作ボタン後の項目を削除
							var jPSize = $('input:hidden[name=pageSize]', jForm);
							jPSize.prev('div[onclick]:empty').remove();
							jPSize.nextAll().andSelf().remove();

							jForm.append(match[1]);
							var jTab = jForm.find('table#viewTable');

							jTab.resizeView(true);
							buttonControl(); // 4.3.4.6 (2009/01/15)
						}
					}
				}
			}

			// 4.3.4.6 (2009/01/15) noTransiton.js_buttonControlとソースを統合
			var buttonControl = function ( isInit ) {
				var jForm = $(oForm);
				var jBtnEnt = jForm.find('input:submit.' + settings.sEntryCls);
//				var jBtnEdit = jForm.find('input:submit.' + settings.sEditCls);

				if( isInit ) {
					jBtnEnt.attr('disabled', 'disabled');
				}
				else {
					// Disable noTrnsEntry(sHybsCmdVal廃止)
					//var jBtnMess = jForm.find('input:submit[value=' + jForm.data($.hybs.defaults.sHybsCmdVal) + ']');
					var jBtnMess = $(jForm.data($.hybs.defaults.sHybsCmd).obj);
					if(jBtnMess.hasClass(settings.sEditCls )) { jBtnEnt.removeAttr('disabled'); }
					if(jBtnMess.hasClass(settings.sEntryCls)) { jBtnEnt.attr('disabled', 'disabled'); }
				}
			}

			var mParams = {};
			// 処理先のJSPを自動でnoTransitionモードにする
			// 2009/08/01 リクエスト送信をやめる
			// 5.1.3.0 (2010/02/01) リクエストに戻す
			mParams[settings.sNoTsKey] = 'true';

			/*-------------------------------------------------
				form Plugin のパラメーター設定
			---------------------------------------------------*/
			var formOpts = {};
			formOpts.data = mParams;

			// submit前
			formOpts.beforeSubmit = function (formData, jqForm, options) {
			/* -----------------------------------------
				// 画面に押された操作ボタンのcommandをを取得
				var sName = settings.sHybsCmd;
				var aPair = $.grep(formData, function(a){return (a.name == sName);});
				if(aPair) {
						sName = 'hX_' + aPair[0].value + 'CMD';
						aPair = $.grep(formData, function(a){return (a.name == sName);});
				}
				jqForm[0].hCMD = (aPair) ? aPair[0].value : '';
			   ----------------------------------------- */

				return (settings.beforeSubmit) ? settings.beforeSubmit(formData, jqForm, options) : true;
			};

			// 成功時
			formOpts.success = function(data, status, $form) {
				//var sHybsCmd = $form.data($.hybs.defaults.sHybsCmd);
				// 2009/02/09 $.hybs.defaults.sHybsCmd中のオブジェクト変更
				var sHybsCmd = $form.data($.hybs.defaults.sHybsCmd).cmd;

				// サーバーから帰ってきたデータにrow_errorの有無を確認する
				if(data.indexOf("row_error") >=0) {
					//var match = /(?:<\/table>)*[\S\s]*(\[\d+ - \d+\]\/\[\d+\][\S\s]*<table[^>]*?>[\S\s]+?row_error[\S\s]*<\/table>)/m.exec(data);
					//$.hybs.ogAlert(match ? match[1] : data);
					var match = /(?:<\/table>)*[\S\s]*(\[\d+ - \d+\]\/\[\d+\])[\S\s]*(<table[^>]*?>[\S\s]+?row_error[\S\s]*<\/table>)/m.exec(data);
					$.hybs.ogAlert(match ? (match[1] + match[2]) : data);
				}
				// 5.1.5.0 (2010/04/01)
				else if($.inArray(sHybsCmd, [settings.sCmdInsert, settings.sCmdInsertOne, settings.sCmdCopy, settings.sCmdModify, settings.sCmdDelete
																												, settings.sCmdEntry, settings.sCmdUndo]) >= 0) {
					var bSpecialCase = false;
					// command=ENTRYでサーバーから帰ってきたデータにid="noTransitionUrl"が有れば、そのURLの画面に遷移する
					if(sHybsCmd == settings.sCmdEntry) {
						var match = /<div id="noTransitionUrl">(.*)<\/div><div id="noTransitionTarget">(.*)<\/div>/m.exec(data);
						if(match) {
							var sUrl = match[1];
							var sFrame = match[2];
							// 4.3.3.5 (2008/11/08)
//							var oFrame = (sFrame && top.frames[sFrame]) ? top.frames[sFrame] : window;
							var oFrame = ( sFrame != "null" ) ? eval( "top." + sFrame ) : window;
							oFrame.location.href = sUrl;
							bSpecialCase = true;
						}
					}
					if(!bSpecialCase) {
						var jTab = $form.find('table#viewTable'), jTr1st = jTab.find('tbody tr:first'); // tbody tr:first tbodyの直下の1番目のtr
						// viewTableが存在するかつ行が1行以上ある
						if(jTr1st[0]) { operateOnRows(jTab, jTr1st, sHybsCmd, data); }
						// viewTableが存在する(ヘッダーのみ)
						else if (jTab[0]) { addToNoTBody(jTab, sHybsCmd, data); }
						// viewTableが存在しない
						else { addToNoTable($form, sHybsCmd, data); }
					}
				}
			};

			// エラー発生時
			formOpts.error = function (xhr, status, e) {
				$.hybs.ogLog(status + '\n' + xhr.responseText);

				$.hybs.ogAlert(status + '<br/>' + xhr.responseText);
			};

			// 送信し、データが戻された後の完了処理
			formOpts.complete = function (xhr, status) {
				// クリックしたボタン情報をクリア
				$(oForm).removeData($.hybs.defaults.sHybsCmd);
			}

			// 5.1.5.0 (2010/04/01)
			formOpts.cmds = formOpts.cmds || 
						[settings.sCmdInsert, settings.sCmdInsertOne, settings.sCmdCopy, settings.sCmdModify, settings.sCmdDelete
						, settings.sCmdEntry, settings.sCmdUndo];

			// 4.3.4.6 (2009/01/15)
			buttonControl( true );

			//ajaxFormを呼び出す
			$(oForm).ajaxHybsForm(formOpts);
		});
	};

})(jQuery);

