// ==========================================================================
// $Id: weakptr.cpp,v 1.1 2013/11/24 22:50:26 jlang Exp $
// CSI2372 example Code for lecture 15 - C++11
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   EECS, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: weakptr.cpp,v $
// Revision 1.1  2013/11/24 22:50:26  jlang
// Added examples on weak and unique ptr.
//
// ==========================================================================
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
#include <fstream>
#include <memory>

using std::string;
using std::ostream;
using std::ifstream;
using std::cout;
using std::cerr;
using std::endl;


class Text {
  std::shared_ptr<std::vector<string> > d_text;
public:
  Text(std::shared_ptr<std::vector<string> > _in) : d_text(_in) {
    cout << "Text( _in )" << endl;
  }
  void printSharedStatus( ostream& os ){
  	if (d_text) {
			os << "Number of shares: " << d_text.use_count() << endl;
  	}	
  }
};

class TextOp {
	std::weak_ptr<std::vector<string> > d_text;
public:
  TextOp(std::weak_ptr<std::vector<string> > _in) : d_text(_in) {
    cout << "TextOp( _in )" << endl;
  }
	bool reverse() {
		// get lock on the weak ptr to get shared access
		if ( auto shPtr = d_text.lock()) {
			// use algorithm
			std::reverse(shPtr->begin(),shPtr->end());
		}
		// Our shared ptr goes out of scope again
	}
  int numWords() const {
		if ( auto shPtr = d_text.lock()) {
	  	return shPtr->size();
		}
		return -1;
  }
  // synthesized cctor and destructor are fine
  friend ostream& operator<<(ostream& os, const TextOp& _obj ) {
		if ( auto shPtr = _obj.d_text.lock()) {
      os << "Text: " << _obj.numWords() << " words" << endl;
		  for ( auto word : *(shPtr)) {
			  os << word << " ";
		  };
		} else {
			os << "Could not get share" << endl;
		}
		os << endl;
    return os;
  }	
};



// Read a file into a vector of strings
std::shared_ptr<std::vector<string> > fileIntoVector( string inFileName ) {
  ifstream inFile( inFileName.c_str());
  if ( !inFile ) {
    cerr << "Error: unable to open: " << inFileName << endl;
    return nullptr;
  }
  auto res = std::make_shared<std::vector<string> >();
  string word;
  while( !inFile.eof() ) { 
    inFile >> word;
    if (inFile) res->push_back(word);
  }  
  inFile.clear();
  inFile.close();
  return res;
}



int main( int argc, char** argv ) {
  string inFileName = "in.txt";
  if (argc>1) inFileName = argv[1];
  auto vecPtr = fileIntoVector( inFileName );
  if (!vecPtr) {
  	cerr << "File read produced empty vector" << endl;
  	return -1;
  } 
  TextOp tOp(vecPtr);
	{ 
  	Text text(vecPtr);
  	vecPtr.reset(); // We don't need vecPtr anymore
  	text.printSharedStatus(cout);
  	cout << tOp;
  	tOp.reverse();
  	cout << tOp;
  }
  // Return in original order and print
  // if shared pointer still there
  tOp.reverse(); 
	cout << tOp;
  return 0;
}
