// File: Luthaf[P]zeopp/area_and_volume.cc
// Function: NEWcalcAV(MATERIAL*, double, int, double, double)
double NEWcalcAV(MATERIAL *Mat, double r_probe, int numSamples, double low_dist_cutoff, double high_dist_cutoff){

  // Inital checks
  if(!(Mat->accessAnalysis.alreadySegmentedFlag))
      {
      cerr << "Cannot run calcAV without prior accessibility analysis.\nExiting with return 0\n";
      return 0;
      }

  // Setting parameters
  Mat->AVprobeRadius = r_probe;

  // Cleaning structures in case of previous runs
  Mat->AVcount = 0; 
  Mat->AVcount_inaxs = 0; 
  Mat->AVcount_within_range = 0; 
  Mat->AVcount_outside_range = 0;
  Mat->AVaxsPoints.clear(); 
  Mat->AVaxsPointsChannelIDs.clear(); 
  Mat->AVinaxsPoints.clear(); 
  Mat->AVinaxsPointsPocketIDs.clear(); 
  Mat->AVcount_inChannel.clear();
  Mat->AVcount_inPocket.clear();


  //determine whether we are only sampling volume within a specific distance range of the surface
  bool within_range = false;
  if(!(low_dist_cutoff<0 || high_dist_cutoff<0)) {
    if(high_dist_cutoff<low_dist_cutoff) { //swap them
      double temp = low_dist_cutoff;
      low_dist_cutoff = high_dist_cutoff;
      high_dist_cutoff = temp;
    }
    within_range = true;
  }

  Mat->AVwithin_rangeFlag = within_range;

  // setting up MC sampling
  srand(randSeed);

  numSamples = int(numSamples * calcDeterminant(Mat->atmnet.ucVectors));
  Mat->AVnumSamples = numSamples;

  cout << "Number of samples in volume calc: " << numSamples << endl;

  bool excludePockets = true; // this is default (in old version, without voro-stuff it was used)

  int count = 0;
  int count_inaxs = 0;
  int count_within_range = 0;
  int count_outside_range = 0;

  // MC statistics can be collected w.r.t to identified channels and inaccessible pockets
  Mat->AVcount_inChannel.resize(Mat->accessAnalysis.n_channels,0);
  Mat->AVcount_inPocket.resize(Mat->accessAnalysis.n_pockets,0);

  for(int i = 0; i < numSamples; i++){
    bool overlaps = false;
    bool inside = false;

    // Randomly sample point across the unit cell
    double aPoint = (rand()*1.0)/RAND_MAX;
    double bPoint = (rand()*1.0)/RAND_MAX;
    double cPoint = (rand()*1.0)/RAND_MAX;

    // Convert coords relative to the unit cell vectors into (x,y,z) coords
    Point samplingPoint = Mat->atmnet.abc_to_xyz(aPoint, bPoint, cPoint);

    // Calling accessibility object to determine accessibility of the point (this replaced a big chunk of code by Thomas)
    pair<bool,bool> answer = (Mat->accessAnalysis.isVPointInsideAtomAndNotAccessible(samplingPoint));
    inside = answer.first; overlaps = answer.second;
    if(Mat->accessAnalysis.needToResample() == true) i--; // the sampled point could not be analyzed in isVPointInsideAtomAndNotAccessible() function, resampling needed

    if(inside == false && excludePockets == false) overlaps = false; // if ignore inacceible pockets, treat the point as accessible (unless inside atom)
      
    // Store sampled points that did not overlap with an atom but were inaccessible for later visualization
    if(Mat->accessAnalysis.needToResample() == false && !inside && overlaps){
      count_inaxs++;
      pair <int,int> CoP = Mat->accessAnalysis.lastChannelOrPocket();
      if(CoP.first!=-1) 
        {
        cout << "Error: CoP.first!=-1 in pocket, consult source code provider\n";
        } else {
        Mat->AVcount_inPocket[CoP.second]++;
        };
      if(!within_range) {
        //Point abcCoords = Point(aPoint, bPoint, cPoint); // to be removed as now we store fractional coordinates
        //Point coords = Mat->atmnet.abc_to_xyz(abcCoords);
        Point coords = Point(aPoint, bPoint, cPoint);
        Mat->AVinaxsPoints.push_back(coords);
        Mat->AVinaxsPointsPocketIDs.push_back(CoP.second);
      };
    };

    // Store accessible points for later visualization
    if(Mat->accessAnalysis.needToResample() == false && !overlaps) {
      count++;     
      pair <int,int> CoP = Mat->accessAnalysis.lastChannelOrPocket();
      if(CoP.second!=-1) 
        {
        cout << "Error: CoP.second!=-1 in channel, consult source code provider\n";
        } else {
        Mat->AVcount_inChannel[CoP.first]++;
        };
      //Point abcCoords = Point(aPoint, bPoint, cPoint);  // to be removed as now we store fractional coordinates
      //Point coords = Mat->atmnet.abc_to_xyz(abcCoords);
      Point coords = Point(aPoint, bPoint, cPoint);
      if(within_range) {
        if(Mat->accessAnalysis.lastMinDist() >= low_dist_cutoff && Mat->accessAnalysis.lastMinDist() <= high_dist_cutoff) { //NOTE: minDist is the distance between centroids, it is NOT the distance to the surface - here we are comparing this distance to the tolerance range
                                                                               // RECHECK IF STILL TRUE FOR NON INFLATED ATOMS
          count_within_range++;
          Mat->AVaxsPoints.push_back(coords);
        } else {
          count_outside_range++;
          Mat->AVinaxsPoints.push_back(coords);
        }
      } else 
      {
      Mat->AVaxsPoints.push_back(coords); 
      Mat->AVaxsPointsChannelIDs.push_back(CoP.first);
      };
    }
  }; // ends a for loop over all sampled points

  // Warn user if points were resampled
  int resampleCount =  Mat->accessAnalysis.getResampleCount();
  if(resampleCount != 0){
    cerr << "\n" << "\n"
         << "Warning: Resampled " << resampleCount << " points out of " << numSamples
         << " when analyzing " << Mat->atmnet.name << "\n"
         << "\n" << "\n";
  };

  Mat->AVcount = count;
  Mat->AVcount_inaxs = count_inaxs;
  Mat->AVcount_within_range = count_within_range;
  Mat->AVcount_outside_range = count_outside_range;


  return count/numSamples;

}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movq %rdi, -0x10(%rbp)
movsd %xmm0, -0x18(%rbp)
movl %esi, -0x1c(%rbp)
movsd %xmm1, -0x28(%rbp)
movsd %xmm2, -0x30(%rbp)
movq -0x10(%rbp), %rax
testb $0x1, 0xb1d(%rax)
jne 0x7a50e
movq 0x1f8afb(%rip), %rdi    # 0x272ff0
leaq 0x17c54c(%rip), %rsi    # 0x1f6a48
callq 0x5540
xorps %xmm0, %xmm0
movsd %xmm0, -0x8(%rbp)
jmp 0x7aba8
movsd -0x18(%rbp), %xmm0
movq -0x10(%rbp), %rax
movsd %xmm0, 0xc70(%rax)
movq -0x10(%rbp), %rax
movl $0x0, 0xc7c(%rax)
movq -0x10(%rbp), %rax
movl $0x0, 0xc80(%rax)
movq -0x10(%rbp), %rax
movl $0x0, 0xc84(%rax)
movq -0x10(%rbp), %rax
movl $0x0, 0xc88(%rax)
movq -0x10(%rbp), %rdi
addq $0xc90, %rdi            # imm = 0xC90
callq 0x84ae0
movq -0x10(%rbp), %rdi
addq $0xca8, %rdi            # imm = 0xCA8
callq 0x163b0
movq -0x10(%rbp), %rdi
addq $0xcc0, %rdi            # imm = 0xCC0
callq 0x84ae0
movq -0x10(%rbp), %rdi
addq $0xcd8, %rdi            # imm = 0xCD8
callq 0x163b0
movq -0x10(%rbp), %rdi
addq $0xcf0, %rdi            # imm = 0xCF0
callq 0x163b0
movq -0x10(%rbp), %rdi
addq $0xd08, %rdi            # imm = 0xD08
callq 0x163b0
movb $0x0, -0x31(%rbp)
xorps %xmm0, %xmm0
ucomisd -0x28(%rbp), %xmm0
ja 0x7a601
xorps %xmm0, %xmm0
ucomisd -0x30(%rbp), %xmm0
ja 0x7a601
movsd -0x30(%rbp), %xmm1
movsd -0x28(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x7a5fd
movsd -0x28(%rbp), %xmm0
movsd %xmm0, -0x40(%rbp)
movsd -0x30(%rbp), %xmm0
movsd %xmm0, -0x28(%rbp)
movsd -0x40(%rbp), %xmm0
movsd %xmm0, -0x30(%rbp)
movb $0x1, -0x31(%rbp)
movb -0x31(%rbp), %cl
movq -0x10(%rbp), %rax
andb $0x1, %cl
movb %cl, 0xc8c(%rax)
movl $0x3b4ca6f5, %edi       # imm = 0x3B4CA6F5
callq 0x5510
cvtsi2sdl -0x1c(%rbp), %xmm0
movsd %xmm0, -0x108(%rbp)
movq -0x10(%rbp), %rdi
addq $0x80, %rdi
callq 0xe9390
movaps %xmm0, %xmm1
movsd -0x108(%rbp), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc78(%rax)
movq 0x1f895e(%rip), %rdi    # 0x272fc0
leaq 0x17c42e(%rip), %rsi    # 0x1f6a97
callq 0x5540
movq %rax, %rdi
movl -0x1c(%rbp), %esi
callq 0x58d0
movq %rax, %rdi
movq 0x1f8915(%rip), %rsi    # 0x272f98
callq 0x55b0
movb $0x1, -0x41(%rbp)
movl $0x0, -0x48(%rbp)
movl $0x0, -0x4c(%rbp)
movl $0x0, -0x50(%rbp)
movl $0x0, -0x54(%rbp)
movq -0x10(%rbp), %rdi
addq $0xcf0, %rdi            # imm = 0xCF0
movq -0x10(%rbp), %rax
movslq 0xa68(%rax), %rsi
movl $0x0, -0x58(%rbp)
leaq -0x58(%rbp), %rdx
callq 0x84b00
movq -0x10(%rbp), %rdi
addq $0xd08, %rdi            # imm = 0xD08
movq -0x10(%rbp), %rax
movslq 0xa6c(%rax), %rsi
movl $0x0, -0x5c(%rbp)
leaq -0x5c(%rbp), %rdx
callq 0x84b00
movl $0x0, -0x60(%rbp)
movl -0x60(%rbp), %eax
cmpl -0x1c(%rbp), %eax
jge 0x7aa99
movb $0x0, -0x61(%rbp)
movb $0x0, -0x62(%rbp)
callq 0x5190
cvtsi2sd %eax, %xmm0
movsd 0x177930(%rip), %xmm1   # 0x1f2050
mulsd %xmm1, %xmm0
movsd 0x17bedc(%rip), %xmm1   # 0x1f6608
divsd %xmm1, %xmm0
movsd %xmm0, -0x70(%rbp)
callq 0x5190
cvtsi2sd %eax, %xmm0
movsd 0x17790a(%rip), %xmm1   # 0x1f2050
mulsd %xmm1, %xmm0
movsd 0x17beb6(%rip), %xmm1   # 0x1f6608
divsd %xmm1, %xmm0
movsd %xmm0, -0x78(%rbp)
callq 0x5190
cvtsi2sd %eax, %xmm0
movsd 0x1778e4(%rip), %xmm1   # 0x1f2050
mulsd %xmm1, %xmm0
movsd 0x17be90(%rip), %xmm1   # 0x1f6608
divsd %xmm1, %xmm0
movsd %xmm0, -0x80(%rbp)
movq -0x10(%rbp), %rsi
movsd -0x70(%rbp), %xmm0
movsd -0x78(%rbp), %xmm1
movsd -0x80(%rbp), %xmm2
leaq -0x98(%rbp), %rdi
callq 0x97170
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
movq -0x98(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x88(%rbp), %rax
movq %rax, -0xa8(%rbp)
leaq -0xb8(%rbp), %rax
movq (%rax), %rcx
movq %rcx, (%rsp)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0xfee30
movw %ax, -0x9a(%rbp)
movb -0x9a(%rbp), %al
andb $0x1, %al
movb %al, -0x62(%rbp)
movb -0x99(%rbp), %al
andb $0x1, %al
movb %al, -0x61(%rbp)
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84bb0
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x7a83a
movl -0x60(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x60(%rbp)
movb -0x62(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x7a858
movb -0x41(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x7a858
movb $0x0, -0x61(%rbp)
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84bb0
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x7a93b
testb $0x1, -0x62(%rbp)
jne 0x7a93b
testb $0x1, -0x61(%rbp)
je 0x7a93b
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84c20
movq %rax, -0xc0(%rbp)
cmpl $-0x1, -0xc0(%rbp)
je 0x7a8c8
movq 0x1f8706(%rip), %rdi    # 0x272fc0
leaq 0x17be5f(%rip), %rsi    # 0x1f6720
callq 0x5540
jmp 0x7a8e6
movq -0x10(%rbp), %rdi
addq $0xd08, %rdi            # imm = 0xD08
movslq -0xbc(%rbp), %rsi
callq 0xed60
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
testb $0x1, -0x31(%rbp)
jne 0x7a939
movsd -0x70(%rbp), %xmm0
movsd -0x78(%rbp), %xmm1
movsd -0x80(%rbp), %xmm2
leaq -0xd8(%rbp), %rdi
callq 0xe9c70
movq -0x10(%rbp), %rdi
addq $0xcc0, %rdi            # imm = 0xCC0
leaq -0xd8(%rbp), %rsi
callq 0x59bf0
movq -0x10(%rbp), %rdi
addq $0xcd8, %rdi            # imm = 0xCD8
leaq -0xc0(%rbp), %rsi
addq $0x4, %rsi
callq 0xd1b0
jmp 0x7a93b
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84bb0
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x7aa89
testb $0x1, -0x61(%rbp)
jne 0x7aa89
movl -0x48(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48(%rbp)
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84c20
movq %rax, -0xe0(%rbp)
cmpl $-0x1, -0xdc(%rbp)
je 0x7a9a1
movq 0x1f862d(%rip), %rdi    # 0x272fc0
leaq 0x17bdc4(%rip), %rsi    # 0x1f675e
callq 0x5540
jmp 0x7a9bf
movq -0x10(%rbp), %rdi
addq $0xcf0, %rdi            # imm = 0xCF0
movslq -0xe0(%rbp), %rsi
callq 0xed60
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movsd -0x70(%rbp), %xmm0
movsd -0x78(%rbp), %xmm1
movsd -0x80(%rbp), %xmm2
leaq -0xf8(%rbp), %rdi
callq 0xe9c70
testb $0x1, -0x31(%rbp)
je 0x7aa59
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84d90
ucomisd -0x28(%rbp), %xmm0
jb 0x7aa37
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84d90
movaps %xmm0, %xmm1
movsd -0x30(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x7aa37
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
addq $0xc90, %rdi            # imm = 0xC90
leaq -0xf8(%rbp), %rsi
callq 0x59bf0
jmp 0x7aa57
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
movq -0x10(%rbp), %rdi
addq $0xcc0, %rdi            # imm = 0xCC0
leaq -0xf8(%rbp), %rsi
callq 0x59bf0
jmp 0x7aa87
movq -0x10(%rbp), %rdi
addq $0xc90, %rdi            # imm = 0xC90
leaq -0xf8(%rbp), %rsi
callq 0x59bf0
movq -0x10(%rbp), %rdi
addq $0xca8, %rdi            # imm = 0xCA8
leaq -0xe0(%rbp), %rsi
callq 0xd1b0
jmp 0x7aa89
jmp 0x7aa8b
movl -0x60(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x60(%rbp)
jmp 0x7a6fb
movq -0x10(%rbp), %rdi
addq $0x990, %rdi            # imm = 0x990
callq 0x84db0
movl %eax, -0xfc(%rbp)
cmpl $0x0, -0xfc(%rbp)
je 0x7ab64
movq 0x1f852d(%rip), %rdi    # 0x272ff0
leaq 0x17eb5b(%rip), %rsi    # 0x1f9625
callq 0x5540
movq %rax, %rdi
leaq 0x17eb4c(%rip), %rsi    # 0x1f9625
callq 0x5540
movq %rax, %rdi
leaq 0x17bcb6(%rip), %rsi    # 0x1f679e
callq 0x5540
movq %rax, %rdi
movl -0xfc(%rbp), %esi
callq 0x58d0
movq %rax, %rdi
leaq 0x17bcad(%rip), %rsi    # 0x1f67b2
callq 0x5540
movq %rax, %rdi
movl -0x1c(%rbp), %esi
callq 0x58d0
movq %rax, %rdi
leaq 0x18ec56(%rip), %rsi    # 0x209775
callq 0x5540
movq %rax, %rdi
movq -0x10(%rbp), %rsi
addq $0x320, %rsi            # imm = 0x320
callq 0x5480
movq %rax, %rdi
leaq 0x17eae4(%rip), %rsi    # 0x1f9625
callq 0x5540
movq %rax, %rdi
leaq 0x17ead5(%rip), %rsi    # 0x1f9625
callq 0x5540
movq %rax, %rdi
leaq 0x17eac6(%rip), %rsi    # 0x1f9625
callq 0x5540
movl -0x48(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc7c(%rax)
movl -0x4c(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc80(%rax)
movl -0x50(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc84(%rax)
movl -0x54(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc88(%rax)
movl -0x48(%rbp), %eax
cltd
idivl -0x1c(%rbp)
cvtsi2sd %eax, %xmm0
movsd %xmm0, -0x8(%rbp)
movsd -0x8(%rbp), %xmm0
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
nopw %cs:(%rax,%rax)