using System; using System.Collections; using System.Data.OracleClient; using TRACEROBJECTLib; namespace CCSTrace.CCS.EventAI { public class TraceSubject { private string _mDbConnectionString; private static bool _isNewCase; private static ArrayList _mLinkList; // store the switch of the new case path private static TraceEngine _mTEngine; private static Hashtable _mTreeMap; // store the switch of the old case path private static int _sFsc; private static int _sUfid; private readonly RecordLog _plogger; private readonly ArrayList _mTmp = new ArrayList(); private NetworkContext _mPContext; private readonly OracleConnection _connectionTpc; private readonly OracleTransaction _transaction; public TraceSubject(OracleConnection conn, OracleTransaction trx, string traceConnectionString, RecordLog log) { _connectionTpc = conn; _transaction = trx; _plogger = log; _mDbConnectionString = traceConnectionString; try { if (_mTEngine == null) { _mTEngine = new TraceEngine(); } } catch (Exception ex) { _plogger.Error(ex.Message); throw ex; } } public void DiscardEngine() { _mTEngine = null; } public ArrayList GetNewResult() { return _mLinkList; } public Hashtable GetOldResult() { return _mTreeMap; } // for EOS(only get the reverse tree) public void StartTrace(int startFsc, int startUfid, bool mIsNew) { _sFsc = startFsc; _sUfid = startUfid; _isNewCase = mIsNew; _mTreeMap = new Hashtable(); _mLinkList = new ArrayList(); try { SetReverseTree(Trace(true)); } catch (Exception e) { _plogger.Error(e.Message); Console.WriteLine(e.StackTrace); throw e; } } private bool GetSwitchOn(int ufid) { var sqlStmt = "SELECT M.OSTATUS as OSTATUS FROM (SELECT UFID,OSTATUS FROM BASEDB.CONNECTIVITY WHERE FSC = 114) M," + "BASEDB.SWITCH S WHERE M.UFID = S.UFID AND S.NSTATUS <> 0 AND M.UFID = " + ufid; OracleCommand command = null; OracleDataReader reader = null; try { command = new OracleCommand(sqlStmt, _connectionTpc, _transaction); reader = command.ExecuteReader(); if (reader.Read()) { if (Convert.ToInt32(reader["OSTATUS"]) == 1) return true; } reader.Close(); } catch (Exception e) { _plogger.Error(e.Message); Console.WriteLine(e.StackTrace); } finally { command?.Dispose(); reader?.Close(); } return false; } private bool GetJumperOn(int ufid) { var sqlStmt = "SELECT OSTATUS FROM BASEDB.CONNECTIVITY WHERE FSC = 109 AND UFID = " + ufid; OracleCommand command = null; OracleDataReader reader = null; try { command = new OracleCommand(sqlStmt, _connectionTpc, _transaction); reader = command.ExecuteReader(); if (reader.Read()) { if (Convert.ToInt32(reader["OSTATUS"]) == 1) return true; } reader.Close(); } catch (Exception e) { _plogger.Error(e.Message); Console.WriteLine(e.StackTrace); } finally { if (command != null) command.Dispose(); if (reader != null) reader.Close(); } return false; } private readonly Hashtable _traceCounts = new Hashtable(); private void SetReverseTree(ResultTree tree) { int i = 0; TreeIterator iti = null; bool ostatus = true; if (tree != null) { i = 0; iti = tree.CreateTreeIterator(); bool isNotEnd = true; while (isNotEnd) { if (GetTraceCount(iti.Value.ClassID, iti.Value.ObjectID) > 5) throw new TraceLoopException("追蹤產生迴圈狀況。(Fsc,Ufid) = (" + iti.Value.ClassID + "," + iti.Value.ObjectID + ")"); else AddTraceCount(iti.Value.ClassID, iti.Value.ObjectID); while (iti.IsLeaf == 0) { TreeNode node = iti.Value; if ((node.ClassID == 114) || (node.ClassID == 108) || (node.ClassID == 109)) { Equipment equip = new Equipment(node.ClassID, node.ObjectID); if (_isNewCase) _mLinkList.Add(equip); else { _mTreeMap.Add(node.ObjectID, equip); _mTmp.Add(equip); } i++; /* if (getTraceCount(node.ClassID, node.ObjectID) > 2) throw new Exception("追蹤產生迴圈狀況。(Fsc,Ufid) = (" + node.ClassID + "," + node.ObjectID + ")"); else AddTraceCount(node.ClassID, node.ObjectID); */ } Console.WriteLine(node.ClassID + "----->" + node.ObjectID); _plogger.Info(node.ClassID + "----->" + node.ObjectID); iti.MoveDescent((short)0); } // 當從breaker出來的導線不只一條時,breaker可能會不被add(因為breaker是leaf但其parent的DescentCount > 1,所以被忽略) /* * if ( ((com.origo.TraceModel.ITreeNode)iti.get_Value()).get_ClassID() == EOS.GlobalVariable.Breaker ) { * com.origo.TraceModel.ITreeNode node = iti.get_Value(); Equipment Equip = new Equipment(node.get_ClassID(),node.get_ObjectID()); if ( * IsNewCase ) m_LinkList.add(i,Equip); else { m_TreeMap.put(new Integer(node.get_ObjectID()),Equip); m_Tmp.add(Equip); } * System.out.println(node.get_ClassID() + "----->" + node.get_ObjectID()); System.out.println("Trace Finish...."); i++; break; } */ if ((iti.Value).ClassID == GlobalVariable.Breaker) { TreeNode node = iti.Value; Equipment equip = new Equipment(node.ClassID, node.ObjectID); if (_isNewCase) _mLinkList.Add(equip); else { _mTreeMap.Add(node.ObjectID, equip); _mTmp.Add(equip); } i++; //後面直接就FINISH,所以就不用判斷tracecount Console.WriteLine(node.ClassID + "----->" + node.ObjectID); _plogger.Info(node.ClassID + "----->" + node.ObjectID); Console.WriteLine("Trace Finish...."); _plogger.Info("Trace Finish...."); break; } // 當追蹤到被切開的開關且該上一層設備只有該開關一個child) else if (iti.Value.ClassID == GlobalVariable.Switch || iti.Value.ClassID == GlobalVariable.Jumper) { TreeNode node = iti.Value; iti.MoveAscent(); Equipment equip = new Equipment(node.ClassID, node.ObjectID); if (IsEndEquip(equip)) { if (_isNewCase) _mLinkList.Add(equip); else { _mTreeMap.Add(node.ObjectID, equip); _mTmp.Add(equip); } i++; //後面直接就FINISH,所以就不用判斷tracecount Console.WriteLine(node.ClassID + "----->" + node.ObjectID); _plogger.Info(node.ClassID + "----->" + node.ObjectID); Console.WriteLine("Trace Finish...."); _plogger.Info("Trace Finish...."); break; } //switch (node.ClassID) //{ // case 114: // ostatus = getSwitchOn(node.ObjectID); // break; // case 109: // ostatus = getJumperOn(node.ObjectID); // break; //} //if (!ostatus && (iti.DescentCount == 1)) { // Equipment Equip = new Equipment(node.ClassID, node.ObjectID); // if (IsNewCase) // m_LinkList.Add(Equip); // else { // m_TreeMap.Add(node.ObjectID, Equip); // m_Tmp.Add(Equip); // } // i++; // Console.WriteLine(node.ClassID + "----->" + node.ObjectID); // _Plogger.Info(node.ClassID + "----->" + node.ObjectID); // Console.WriteLine("Trace Finish...."); // _Plogger.Info("Trace Finish...."); // break; //} } else { TreeNode node = iti.Value; iti.MoveAscent(); if (iti.DescentCount == 1) throw new Exception("追蹤到非開關類斷開之設備(Fsc = " + node.ClassID + ",Ufid = " + node.ObjectID); } for (int j = 1; j < iti.DescentCount; j++) { iti.MoveDescent((short)j); if (iti.IsLeaf == 1) { TreeNode node = iti.Value; Equipment equip = new Equipment(node.ClassID, node.ObjectID); switch (node.ClassID) { case 108: if (_isNewCase) _mLinkList.Add(equip); else { _mTreeMap.Add(node.ObjectID, equip); _mTmp.Add(equip); } Console.WriteLine(node.ClassID + "----->" + node.ObjectID); _plogger.Info(node.ClassID + "----->" + node.ObjectID); i++; /* if (getTraceCount(node.ClassID, node.ObjectID) > 2) throw new Exception("追蹤產生迴圈狀況。(Fsc,Ufid) = (" + node.ClassID + "," + node.ObjectID + ")"); else AddTraceCount(node.ClassID, node.ObjectID); */ break; case 109: case 114: switch (node.ClassID) { case 114: ostatus = GetSwitchOn(node.ObjectID); break; case 109: ostatus = GetJumperOn(node.ObjectID); break; } // Only for switch because the breaker only has one node to descent if (!ostatus) { if (_isNewCase) _mLinkList.Add(equip); else { _mTreeMap.Add(node.ObjectID, equip); _mTmp.Add(equip); } Console.WriteLine(node.ClassID + "----->" + node.ObjectID); _plogger.Info(node.ClassID + "----->" + node.ObjectID); i++; /* if (getTraceCount(node.ClassID, node.ObjectID) > 2) throw new Exception("追蹤產生迴圈狀況。(Fsc,Ufid) = (" + node.ClassID + "," + node.ObjectID + ")"); else AddTraceCount(node.ClassID, node.ObjectID); */ } break; default: break; } // switch iti.MoveAscent(); isNotEnd = false; } else { isNotEnd = true; break; } } // for } // while Console.WriteLine("Tree Node Count = " + i); _plogger.Info("Tree Node Count = " + i); } else { Console.WriteLine("Tree is null"); _plogger.Info("Tree is null"); throw new Exception("無法追蹤到任何設備,可能是該用戶所在變壓器設備連結性有問題。"); } } private ResultTree Trace(bool reverse) { ResultTree tree = null; try { ConfigTrace(); _plogger.Info("configTrace OK."); } catch (Exception e) { _plogger.Error(e.Message); Console.WriteLine(e.StackTrace); return tree; } try { tree = ModeTrace(reverse); } catch (Exception e) { _plogger.Error(e.Message); Console.WriteLine(e.StackTrace); } return tree; } private void ConfigTrace() { if (_mDbConnectionString == null) { _mDbConnectionString = "basedb/basedb000@nntpc"; } try { if (_mPContext == null) _mPContext = _mTEngine.teoCreateContext(); if (_mPContext.IsConnected == 0) { _mPContext.Connect("", _mDbConnectionString); } } catch (Exception ex) { _plogger.Error(ex.Message); } } private ResultTree ModeTrace(bool reverse) { TravelContext tContext = new TravelContext(); TravelStartCriterion sCriterion = new TravelStartCriterion(); TravelTerminateCriterion eCriterion = new TravelTerminateCriterion(); sCriterion.ClsID = (short)_sFsc; sCriterion.ObjID = _sUfid; if (reverse) // 反向上追 { sCriterion.StartMode = (TRAVELSTARTCRITERIONTYPE)(Convert.ToInt32(TRAVELSTARTCRITERIONTYPE.TRAVELBYNEGDIR) + Convert.ToInt32(TRAVELSTARTCRITERIONTYPE.TRAVELWITHFOLLOW)); eCriterion.ClsID = (short)GlobalVariable.Breaker; eCriterion.EndMode = TRAVELTERMCRITERIONTYPE.TRAVELTOTHISCLASS; } else // 順向追蹤 { sCriterion.StartMode = TRAVELSTARTCRITERIONTYPE.TRAVELBYCURDIR; eCriterion.EndMode = TRAVELTERMCRITERIONTYPE.TRAVELTOTHISCLASS; } tContext.addCriterion(sCriterion); tContext.addCriterion(eCriterion); _mPContext.ResetContext(); _plogger.Info("Set ModeTrace OK."); ResultTreeBuilder trBuilder = _mPContext.CreateTreeBuilder(); if (!trBuilder.constructResultTree(tContext, TRAVELTHREADMODE.CONMODE_SYNCHRONOUS)) { return null; } _plogger.Info("ConstructResultTree OK."); ResultTree result = trBuilder.ResultTree; _plogger.Info("getResultTree OK."); return result; } //判斷是否為最終設備(逆向追到已經無child的設備時,檢查該設備是否為最終設備(查驗該設備的同層設備,是否仍有可繼續逆向追蹤的設備,若無,則該設備為最終設備 private bool IsEndEquip(Equipment selfEquip) { string sqlStmt; OracleCommand command = null; OracleDataReader reader = null; long nValue = 0; sqlStmt = "SELECT DIR,OSTATUS,N1,N2 FROM BASEDB.CONNECTIVITY WHERE FSC = " + selfEquip.Fsc+ " AND UFID = " + selfEquip.Ufid; try { command = new OracleCommand(sqlStmt, _connectionTpc, _transaction); reader = command.ExecuteReader(); if (reader.Read()) { if (Convert.ToInt32(reader["OSTATUS"]) == 1) //如果設備本身為非切開的設備,那應該繼續往逆向追 return false; else { if (Convert.ToInt32(reader["DIR"]) == 3) //順向無電 N1-->N2,所以逆向的上游N值抓N2 nValue = Convert.ToInt32(reader["N2"]); else nValue = Convert.ToInt32(reader["N1"]); } } reader.Close(); sqlStmt = "SELECT FSC,UFID,DIR,OSTATUS,N1,N2 FROM BASEDB.CONNECTIVITY WHERE N1 <> N2 AND ( N1 = " + nValue + " OR N2 = " + nValue + ")"; command.CommandText = sqlStmt; reader = command.ExecuteReader(); while (reader.Read()) { if (Convert.ToInt32(reader["FSC"]) == selfEquip.Fsc&& Convert.ToInt32(reader["UFID"]) == selfEquip.Ufid) continue; if (Convert.ToInt32(reader["OSTATUS"]) == 0) //切開的設備不可能為逆向的上游 continue; if (Convert.ToInt32(reader["N1"]) == nValue) { switch (Convert.ToInt32(reader["DIR"])) { case 1: case 3: break; case 2: case 4: return false; //如果逆向的上游連接點為N1,一定要N2-->N1才可能還有需要逆向追蹤設備 case 99: break; //未供電設備不可能是逆向上游 } } else if (Convert.ToInt32(reader["N2"]) == nValue) { switch (Convert.ToInt32(reader["DIR"])) { case 1: case 3: return false; //如果逆向的上游連接點為N2,一定要N1-->N2才可能還有需要逆向追蹤設備 case 2: case 4: break; case 99: return false; //未供電設備不可能是逆向上游 } } } reader.Close(); } catch (Exception e) { _plogger.Error(e.Message); Console.WriteLine(e.StackTrace); return false; } finally { if (command != null) command.Dispose(); if (reader != null) reader.Close(); } return true; } private int GetTraceCount(int fsc, int ufid) { if (_traceCounts.ContainsKey(fsc + "|" + ufid)) return int.Parse(_traceCounts[fsc + "|" + ufid].ToString()); else return 0; } private void AddTraceCount(int fsc, int ufid) { int count = 1; if (_traceCounts.ContainsKey(fsc + "|" + ufid)) { count = int.Parse(_traceCounts[fsc + "|" + ufid].ToString()); count++; _traceCounts.Remove(fsc + "|" + ufid); } _traceCounts.Add(fsc + "|" + ufid, count.ToString()); } } public class TraceLoopException : Exception { public TraceLoopException(string message) : base(message) { } } }