using System; using System.Collections; using System.Data.OracleClient; using NLog; using TRACEROBJECTLib; namespace CCSTrace.CCS.EventAI { public class TraceSubject { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private string _dbConnectionString; private static bool _isNewCase; private static ArrayList _linkList; // store the switch of the new case path private static TraceEngine _traceEngine; private static Hashtable _treeMap; // store the switch of the old case path private static int _sFsc; private static int _sUfid; private readonly ArrayList _tmp = new ArrayList(); private NetworkContext _context; private readonly OracleConnection _connectionTpc; private readonly OracleTransaction _transaction; public TraceSubject(OracleConnection conn, OracleTransaction trx, string traceConnectionString) { _connectionTpc = conn; _transaction = trx; _dbConnectionString = traceConnectionString; try { if (_traceEngine == null) { _traceEngine = new TraceEngine(); } } catch (Exception ex) { Logger.Error(ex, ex.Message); throw; } } public void DiscardEngine() { _traceEngine = null; } public ArrayList GetNewResult() { return _linkList; } public Hashtable GetOldResult() { return _treeMap; } // for EOS(only get the reverse tree) public void StartTrace(int startFsc, int startUfid, bool mIsNew) { _sFsc = startFsc; _sUfid = startUfid; _isNewCase = mIsNew; _treeMap = new Hashtable(); _linkList = new ArrayList(); try { SetReverseTree(Trace(true)); } catch (Exception e) { Logger.Error(e, e.Message); throw; } } 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) { Logger.Error(e, e.Message); } 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) { Logger.Error(e, e.Message); } finally { command?.Dispose(); 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) _linkList.Add(equip); else { _treeMap.Add(node.ObjectID, equip); _tmp.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); */ } Logger.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) _linkList.Add(equip); else { _treeMap.Add(node.ObjectID, equip); _tmp.Add(equip); } i++; //後面直接就FINISH,所以就不用判斷tracecount Logger.Info(node.ClassID + "----->" + node.ObjectID); Logger.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) _linkList.Add(equip); else { _treeMap.Add(node.ObjectID, equip); _tmp.Add(equip); } i++; //後面直接就FINISH,所以就不用判斷tracecount Logger.Info(node.ClassID + "----->" + node.ObjectID); Logger.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) _linkList.Add(equip); else { _treeMap.Add(node.ObjectID, equip); _tmp.Add(equip); } Logger.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) _linkList.Add(equip); else { _treeMap.Add(node.ObjectID, equip); _tmp.Add(equip); } Logger.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 Logger.Info("Tree Node Count = " + i); } else { Logger.Info("Tree is null"); throw new Exception("無法追蹤到任何設備,可能是該用戶所在變壓器設備連結性有問題。"); } } private ResultTree Trace(bool reverse) { ResultTree tree = null; try { ConfigTrace(); Logger.Info("configTrace OK."); } catch (Exception e) { Logger.Error(e, e.Message); return null; } try { tree = ModeTrace(reverse); } catch (Exception e) { Logger.Error(e, e.Message); } return tree; } private void ConfigTrace() { if (_dbConnectionString == null) { _dbConnectionString = "basedb/basedb000@nntpc"; } try { if (_context == null) _context = _traceEngine.teoCreateContext(); if (_context.IsConnected == 0) { _context.Connect("", _dbConnectionString); } } catch (Exception ex) { Logger.Error(ex, 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); _context.ResetContext(); Logger.Info("Set ModeTrace OK."); ResultTreeBuilder trBuilder = _context.CreateTreeBuilder(); if (!trBuilder.constructResultTree(tContext, TRAVELTHREADMODE.CONMODE_SYNCHRONOUS)) { return null; } Logger.Info("ConstructResultTree OK."); ResultTree result = trBuilder.ResultTree; Logger.Info("getResultTree OK."); return result; } //判斷是否為最終設備(逆向追到已經無child的設備時,檢查該設備是否為最終設備(查驗該設備的同層設備,是否仍有可繼續逆向追蹤的設備,若無,則該設備為最終設備 private bool IsEndEquip(Equipment selfEquip) { OracleCommand command = null; OracleDataReader reader = null; long nValue = 0; var 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) { Logger.Error(e, e.Message); return false; } finally { command?.Dispose(); 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) { } } }